Add slide mode with reveal.js

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2021-10-04 12:50:39 +02:00
parent 29565f8f89
commit 36e445e631
70 changed files with 1225 additions and 323 deletions

View file

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { TocAst } from 'markdown-it-toc-done-right'
import { ImageClickHandler } from './replace-components/image/image-replacer'
import { Ref } from 'react'
export interface CommonMarkdownRendererProps {
onFirstHeadingChange?: (firstHeading: string | undefined) => void
onTaskCheckedChange?: (lineInMarkdown: number, checked: boolean) => void
onTocChange?: (ast?: TocAst) => void
baseUrl?: string
onImageClick?: ImageClickHandler
outerContainerRef?: Ref<HTMLDivElement>
useAlternativeBreaks?: boolean
lineOffset?: number
className?: string
content: string
}

View file

@ -4,12 +4,11 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { Ref, useCallback, useMemo, useRef } from 'react'
import React, { useMemo, useRef } from 'react'
import { DocumentLengthLimitReachedAlert } from './document-length-limit-reached-alert'
import { useConvertMarkdownToReactDom } from './hooks/use-convert-markdown-to-react-dom'
import './markdown-renderer.scss'
import { ComponentReplacer } from './replace-components/ComponentReplacer'
import { AdditionalMarkdownRendererProps, LineMarkerPosition } from './types'
import { LineMarkerPosition } from './types'
import { useComponentReplacers } from './hooks/use-component-replacers'
import { useTranslation } from 'react-i18next'
import { LineMarkers } from './replace-components/linemarker/line-number-marker'
@ -18,28 +17,16 @@ import { useExtractFirstHeadline } from './hooks/use-extract-first-headline'
import { TocAst } from 'markdown-it-toc-done-right'
import { useOnRefChange } from './hooks/use-on-ref-change'
import { BasicMarkdownItConfigurator } from './markdown-it-configurator/basic-markdown-it-configurator'
import { ImageClickHandler } from './replace-components/image/image-replacer'
import { useTrimmedContent } from './hooks/use-trimmed-content'
import { CommonMarkdownRendererProps } from './common-markdown-renderer-props'
export interface BasicMarkdownRendererProps {
additionalReplacers?: () => ComponentReplacer[]
onBeforeRendering?: () => void
onAfterRendering?: () => void
onFirstHeadingChange?: (firstHeading: string | undefined) => void
export interface DocumentMarkdownRendererProps extends CommonMarkdownRendererProps {
onLineMarkerPositionChanged?: (lineMarkerPosition: LineMarkerPosition[]) => void
onTaskCheckedChange?: (lineInMarkdown: number, checked: boolean) => void
onTocChange?: (ast?: TocAst) => void
baseUrl?: string
onImageClick?: ImageClickHandler
outerContainerRef?: Ref<HTMLDivElement>
useAlternativeBreaks?: boolean
frontmatterLineOffset?: number
}
export const BasicMarkdownRenderer: React.FC<BasicMarkdownRendererProps & AdditionalMarkdownRendererProps> = ({
export const DocumentMarkdownRenderer: React.FC<DocumentMarkdownRendererProps> = ({
className,
content,
additionalReplacers,
onFirstHeadingChange,
onLineMarkerPositionChanged,
onTaskCheckedChange,
@ -48,7 +35,7 @@ export const BasicMarkdownRenderer: React.FC<BasicMarkdownRendererProps & Additi
onImageClick,
outerContainerRef,
useAlternativeBreaks,
frontmatterLineOffset
lineOffset
}) => {
const markdownBodyRef = useRef<HTMLDivElement>(null)
const currentLineMarkers = useRef<LineMarkers[]>()
@ -64,17 +51,12 @@ export const BasicMarkdownRenderer: React.FC<BasicMarkdownRendererProps & Additi
? undefined
: (lineMarkers) => (currentLineMarkers.current = lineMarkers),
useAlternativeBreaks,
offsetLines: frontmatterLineOffset
lineOffset,
headlineAnchors: true
}).buildConfiguredMarkdownIt(),
[onLineMarkerPositionChanged, useAlternativeBreaks, frontmatterLineOffset]
[onLineMarkerPositionChanged, useAlternativeBreaks, lineOffset]
)
const baseReplacers = useComponentReplacers(onTaskCheckedChange, onImageClick, baseUrl, frontmatterLineOffset)
const replacers = useCallback(
() => baseReplacers().concat(additionalReplacers ? additionalReplacers() : []),
[additionalReplacers, baseReplacers]
)
const replacers = useComponentReplacers(onTaskCheckedChange, onImageClick, baseUrl, lineOffset)
const markdownReactDom = useConvertMarkdownToReactDom(trimmedContent, markdownIt, replacers)
useTranslation()
@ -99,4 +81,4 @@ export const BasicMarkdownRenderer: React.FC<BasicMarkdownRendererProps & Additi
)
}
export default BasicMarkdownRenderer
export default DocumentMarkdownRenderer

View file

@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useCallback } from 'react'
import { useMemo } from 'react'
import { AbcReplacer } from '../replace-components/abc/abc-replacer'
import { AsciinemaReplacer } from '../replace-components/asciinema/asciinema-replacer'
import { ComponentReplacer } from '../replace-components/ComponentReplacer'
@ -41,8 +41,8 @@ export const useComponentReplacers = (
onImageClick?: ImageClickHandler,
baseUrl?: string,
frontmatterLinesToSkip?: number
): (() => ComponentReplacer[]) =>
useCallback(
): ComponentReplacer[] =>
useMemo(
() => [
new LinemarkerReplacer(),
new GistReplacer(),

View file

@ -11,6 +11,7 @@ import { LineKeys } from '../types'
import { buildTransformer } from '../utils/html-react-transformer'
import { calculateNewLineNumberMapping } from '../utils/line-number-mapping'
import convertHtmlToReact from '@hedgedoc/html-to-react'
import { Document } from 'domhandler'
/**
* Renders markdown code into react elements
@ -18,24 +19,19 @@ import convertHtmlToReact from '@hedgedoc/html-to-react'
* @param markdownCode The markdown code that should be rendered
* @param markdownIt The configured {@link MarkdownIt markdown it} instance that should render the code
* @param replacers A function that provides a list of {@link ComponentReplacer component replacers}
* @param onBeforeRendering A callback that gets executed before the rendering
* @param onAfterRendering A callback that gets executed after the rendering
* @param preprocessNodes A function that processes nodes after parsing the html code that is generated by markdown it.
* @return The React DOM that represents the rendered markdown code
*/
export const useConvertMarkdownToReactDom = (
markdownCode: string,
markdownIt: MarkdownIt,
replacers: () => ComponentReplacer[],
onBeforeRendering?: () => void,
onAfterRendering?: () => void
replacers: ComponentReplacer[],
preprocessNodes?: (nodes: Document) => Document
): ValidReactDomElement[] => {
const oldMarkdownLineKeys = useRef<LineKeys[]>()
const lastUsedLineId = useRef<number>(0)
return useMemo(() => {
if (onBeforeRendering) {
onBeforeRendering()
}
const html = markdownIt.render(markdownCode)
const contentLines = markdownCode.split('\n')
const { lines: newLines, lastUsedLineId: newLastUsedLineId } = calculateNewLineNumberMapping(
@ -46,12 +42,7 @@ export const useConvertMarkdownToReactDom = (
oldMarkdownLineKeys.current = newLines
lastUsedLineId.current = newLastUsedLineId
const currentReplacers = replacers()
const transformer = currentReplacers.length > 0 ? buildTransformer(newLines, currentReplacers) : undefined
const rendering = convertHtmlToReact(html, { transform: transformer })
if (onAfterRendering) {
onAfterRendering()
}
return rendering
}, [onBeforeRendering, markdownIt, markdownCode, replacers, onAfterRendering])
const transformer = replacers.length > 0 ? buildTransformer(newLines, replacers) : undefined
return convertHtmlToReact(html, { transform: transformer, preprocessNodes: preprocessNodes })
}, [markdownIt, markdownCode, replacers, preprocessNodes])
}

View file

@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useEffect, useState } from 'react'
import Reveal from 'reveal.js'
import { Logger } from '../../../utils/logger'
import { SlideOptions } from '../../common/note-frontmatter/types'
const log = new Logger('reveal.js')
export const useReveal = (content: string, slideOptions?: SlideOptions): void => {
const [deck, setDeck] = useState<Reveal>()
const [isInitialized, setIsInitialized] = useState<boolean>(false)
useEffect(() => {
if (isInitialized) {
return
}
setIsInitialized(true)
log.debug('Initialize with slide options', slideOptions)
const reveal = new Reveal({})
reveal
.initialize()
.then(() => {
reveal.layout()
reveal.slide(0, 0, 0)
setDeck(reveal)
log.debug('Initialisation finished')
})
.catch((error) => {
log.error('Error while initializing reveal.js', error)
})
}, [isInitialized, slideOptions])
useEffect(() => {
if (!deck) {
return
}
log.debug('Sync deck')
deck.layout()
}, [content, deck])
useEffect(() => {
if (!deck || slideOptions === undefined || Object.keys(slideOptions).length === 0) {
return
}
log.debug('Apply config', slideOptions)
deck.configure(slideOptions)
}, [deck, slideOptions])
}

View file

@ -35,12 +35,15 @@ import { highlightedCode } from '../markdown-it-plugins/highlighted-code'
import { quoteExtraColor } from '../markdown-it-plugins/quote-extra-color'
import { quoteExtra } from '../markdown-it-plugins/quote-extra'
import { documentTableOfContents } from '../markdown-it-plugins/document-table-of-contents'
import { addSlideSectionsMarkdownItPlugin } from '../markdown-it-plugins/reveal-sections'
export interface ConfiguratorDetails {
onToc: (toc: TocAst) => void
onLineMarkers?: (lineMarkers: LineMarkers[]) => void
useAlternativeBreaks?: boolean
offsetLines?: number
lineOffset?: number
headlineAnchors?: boolean
slideSections?: boolean
}
export class BasicMarkdownItConfigurator<T extends ConfiguratorDetails> {
@ -73,7 +76,6 @@ export class BasicMarkdownItConfigurator<T extends ConfiguratorDetails> {
protected configure(markdownIt: MarkdownIt): void {
this.configurations.push(
plantumlWithError,
headlineAnchors,
KatexReplacer.markdownItPlugin,
YoutubeReplacer.markdownItPlugin,
VimeoReplacer.markdownItPlugin,
@ -101,8 +103,16 @@ export class BasicMarkdownItConfigurator<T extends ConfiguratorDetails> {
spoilerContainer
)
if (this.options.headlineAnchors) {
this.configurations.push(headlineAnchors)
}
if (this.options.slideSections) {
this.configurations.push(addSlideSectionsMarkdownItPlugin)
}
if (this.options.onLineMarkers) {
this.configurations.push(lineNumberMarker(this.options.onLineMarkers, this.options.offsetLines ?? 0))
this.configurations.push(lineNumberMarker(this.options.onLineMarkers, this.options.lineOffset ?? 0))
}
this.postConfigurations.push(linkifyExtra, MarkdownItParserDebugger)

View file

@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import MarkdownIt from 'markdown-it/lib'
import Token from 'markdown-it/lib/token'
import StateCore from 'markdown-it/lib/rules_core/state_core'
/**
* This functions adds a 'section close' token at currentTokenIndex in the state's token array,
* replacing the current token, if replaceCurrentToken is true.
* It also returns the currentTokenIndex, that will be increased only if the previous token was not replaced.
*
* @param {number} currentTokenIndex - the current position in the tokens array
* @param {StateCore} state - the state core
* @param {boolean} replaceCurrentToken - if the currentToken should be replaced
*/
const addSectionClose = (currentTokenIndex: number, state: StateCore, replaceCurrentToken: boolean): void => {
const sectionCloseToken = new Token('section', 'section', -1)
state.tokens.splice(currentTokenIndex, replaceCurrentToken ? 1 : 0, sectionCloseToken)
}
/**
* This functions adds a 'section open' token at insertIndex in the state's token array.
*
* @param {number} insertIndex - the index at which the token should be added
* @param {StateCore} state - the state core
*/
const addSectionOpen = (insertIndex: number, state: StateCore): void => {
const sectionOpenToken = new Token('section', 'section', 1)
state.tokens.splice(insertIndex, 0, sectionOpenToken)
}
/**
* Adds a plugin to the given {@link MarkdownIt markdown it instance} that
* replaces splits the content by horizontal lines and groups these blocks into
* html section tags.
*
* @param markdownIt The {@link MarkdownIt markdown it instance} to which the plugin should be added
*/
export const addSlideSectionsMarkdownItPlugin: MarkdownIt.PluginSimple = (markdownIt: MarkdownIt): void => {
markdownIt.core.ruler.push('reveal.sections', (state) => {
let sectionBeginIndex = 0
let lastSectionWasBranch = false
for (let currentTokenIndex = 0; currentTokenIndex < state.tokens.length; currentTokenIndex++) {
const currentToken = state.tokens[currentTokenIndex]
if (currentToken.type !== 'hr') {
continue
}
addSectionOpen(sectionBeginIndex, state)
currentTokenIndex += 1
if (currentToken.markup === '---' && lastSectionWasBranch) {
lastSectionWasBranch = false
addSectionClose(currentTokenIndex, state, false)
currentTokenIndex += 1
} else if (currentToken.markup === '----' && !lastSectionWasBranch) {
lastSectionWasBranch = true
addSectionOpen(sectionBeginIndex, state)
currentTokenIndex += 1
}
addSectionClose(currentTokenIndex, state, true)
sectionBeginIndex = currentTokenIndex + 1
}
addSectionOpen(sectionBeginIndex, state)
addSectionClose(state.tokens.length, state, false)
if (lastSectionWasBranch) {
addSectionClose(state.tokens.length, state, false)
}
return true
})
}

View file

@ -0,0 +1,107 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { DataNode, Document, Element, hasChildren, isComment, isTag, Node } from 'domhandler'
import { Logger } from '../../utils/logger'
const log = new Logger('reveal.js > Comment Node Preprocessor')
const revealCommandSyntax = /^\s*\.(\w*):(.*)$/g
const dataAttributesSyntax = /\s*([\w-]*)=(?:"((?:[^"\\]|\\"|\\)*)"|'([^']*)')/g
/**
* Travels through the given {@link Document}, searches for reveal command comments and applies them.
*
* @param doc The document that should be changed
* @return The edited document
*/
export const processRevealCommentNodes = (doc: Document): Document => {
visitNode(doc)
return doc
}
/**
* Processes the given {@link Node} if it is a comment node. If the node has children then all child nodes will be processed.
* @param node The node to process.
*/
const visitNode = (node: Node): void => {
if (isComment(node)) {
processCommentNode(node)
} else if (hasChildren(node)) {
node.childNodes.forEach((childNode) => visitNode(childNode))
}
}
/**
* Processes the given {@link DataNode html comment} by parsing it, finding the element that should be changed and applies the contained changes.
*
* @param node The node that contains the reveal command.
*/
const processCommentNode = (node: DataNode): void => {
const regexResult = node.data.split(revealCommandSyntax)
if (regexResult.length === 1) {
return
}
const parentNode: Element | null = findTargetElement(node, regexResult[1])
if (!parentNode) {
return
}
for (const dataAttribute of regexResult[2].matchAll(dataAttributesSyntax)) {
const attributeName = dataAttribute[1]
const attributeValue = dataAttribute[2] ?? dataAttribute[3]
if (attributeValue) {
log.debug(
`Add attribute "${attributeName}"=>"${attributeValue}" to node`,
parentNode,
'because of',
regexResult[1],
'selector'
)
parentNode.attribs[attributeName] = attributeValue
}
}
}
/**
* Finds the ancestor element that should be changed based on the given selector.
*
* @param node The node whose ancestor should be found.
* @param selector The found ancestor node or null if no node could be found.
*/
const findTargetElement = (node: Node, selector: string): Element | null => {
if (selector === 'slide') {
return findNearestAncestorSection(node)
} else if (selector === 'element') {
return findParentElement(node)
} else {
return null
}
}
/**
* Returns the parent node if it is an {@link Element}.
*
* @param node the found node or null if no parent node exists or if the parent node isn't an {@link Element}.
*/
const findParentElement = (node: Node): Element | null => {
return node.parentNode !== null && isTag(node.parentNode) ? node.parentNode : null
}
/**
* Looks for the nearest ancestor of the node that is a section element.
*
* @param node the found section node or null if no section ancestor could be found.
*/
const findNearestAncestorSection = (node: Node): Element | null => {
let currentNode = node.parentNode
while (currentNode != null) {
if (isTag(currentNode) && currentNode.tagName === 'section') {
break
}
currentNode = node.parentNode
}
return currentNode
}

View file

@ -11,6 +11,8 @@
@import '../../../../../../node_modules/highlight.js/styles/github-dark';
}
position: relative;
code.hljs {
overflow-x: auto;
background-color: rgba(27, 31, 35, .05);
@ -50,10 +52,10 @@
.linenumber {
display: flex;
}
}
&.showGutter .codeline {
margin: 0 0 0 16px;
.codeline {
margin: 0 0 0 16px;
}
}
&.wrapLines .codeline {

View file

@ -18,13 +18,13 @@ export type LineNumberMarkerOptions = (lineMarkers: LineMarkers[]) => void
* This plugin adds markers to the dom, that are used to map line numbers to dom elements.
* It also provides a list of line numbers for the top level dom elements.
*/
export const lineNumberMarker: (options: LineNumberMarkerOptions, offsetLines: number) => MarkdownIt.PluginSimple =
(options, offsetLines = 0) =>
export const lineNumberMarker: (options: LineNumberMarkerOptions, lineOffset: number) => MarkdownIt.PluginSimple =
(options, lineOffset = 0) =>
(md: MarkdownIt) => {
// add app_linemarker token before each opening or self-closing level-0 tag
md.core.ruler.push('line_number_marker', (state) => {
const lineMarkers: LineMarkers[] = []
tagTokens(state.tokens, lineMarkers, offsetLines)
tagTokens(state.tokens, lineMarkers, lineOffset)
if (options) {
options(lineMarkers)
}
@ -57,7 +57,7 @@ export const lineNumberMarker: (options: LineNumberMarkerOptions, offsetLines: n
tokens.splice(tokenPosition, 0, startToken)
}
const tagTokens = (tokens: Token[], lineMarkers: LineMarkers[], offsetLines: number) => {
const tagTokens = (tokens: Token[], lineMarkers: LineMarkers[], lineOffset: number) => {
for (let tokenPosition = 0; tokenPosition < tokens.length; tokenPosition++) {
const token = tokens[tokenPosition]
if (token.hidden) {
@ -72,14 +72,14 @@ export const lineNumberMarker: (options: LineNumberMarkerOptions, offsetLines: n
const endLineNumber = token.map[1] + 1
if (token.level === 0) {
lineMarkers.push({ startLine: startLineNumber + offsetLines, endLine: endLineNumber + offsetLines })
lineMarkers.push({ startLine: startLineNumber + lineOffset, endLine: endLineNumber + lineOffset })
}
insertNewLineMarker(startLineNumber, endLineNumber, tokenPosition, token.level, tokens)
tokenPosition += 1
if (token.children) {
tagTokens(token.children, lineMarkers, offsetLines)
tagTokens(token.children, lineMarkers, lineOffset)
}
}
}

View file

@ -66,7 +66,7 @@ export const MarkmapFrame: React.FC<MarkmapFrameProps> = ({ code }) => {
}, [code])
return (
<div data-cy={'markmap'}>
<div data-cy={'markmap'} className={'position-relative'}>
<div className={'svg-container'} ref={diagramContainer} />
<div className={'text-right button-inside'}>
<LockButton

View file

@ -0,0 +1,41 @@
/*!
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
// Default mixins and settings -----------------
@import "../../../node_modules/reveal.js/css/theme/template/mixins";
@import "../../../node_modules/reveal.js/css/theme/template/settings";
// ---------------------------------------------
// Override theme settings (see ../template/settings.scss)
$backgroundColor: #191919;
$mainColor: #fff;
$headingColor: #fff;
$mainFontSize: 42px;
$mainFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingTextShadow: none;
$headingLetterSpacing: normal;
$headingTextTransform: uppercase;
$headingFontWeight: 600;
$linkColor: #42affa;
$linkColorHover: lighten($linkColor, 15%);
$selectionBackgroundColor: lighten($linkColor, 25%);
$heading1Size: 2.5em;
$heading2Size: 1.6em;
$heading3Size: 1.3em;
$heading4Size: 1.0em;
// Change text colors against light slide backgrounds
@include light-bg-text-color(#222);
// Theme template ------------------------------
@import "../../../node_modules/reveal.js/css/theme/template/theme";
// ---------------------------------------------

View file

@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { Fragment, useMemo, useRef } from 'react'
import { useConvertMarkdownToReactDom } from './hooks/use-convert-markdown-to-react-dom'
import './markdown-renderer.scss'
import { useComponentReplacers } from './hooks/use-component-replacers'
import { useExtractFirstHeadline } from './hooks/use-extract-first-headline'
import { TocAst } from 'markdown-it-toc-done-right'
import { useOnRefChange } from './hooks/use-on-ref-change'
import { useTrimmedContent } from './hooks/use-trimmed-content'
import { useReveal } from './hooks/use-reveal'
import './slideshow.scss'
import { ScrollProps } from '../editor-page/synced-scroll/scroll-props'
import { DocumentLengthLimitReachedAlert } from './document-length-limit-reached-alert'
import { BasicMarkdownItConfigurator } from './markdown-it-configurator/basic-markdown-it-configurator'
import { SlideOptions } from '../common/note-frontmatter/types'
import { processRevealCommentNodes } from './process-reveal-comment-nodes'
import { CommonMarkdownRendererProps } from './common-markdown-renderer-props'
export interface SlideshowMarkdownRendererProps extends CommonMarkdownRendererProps {
slideOptions: SlideOptions
}
export const SlideshowMarkdownRenderer: React.FC<SlideshowMarkdownRendererProps & ScrollProps> = ({
className,
content,
onFirstHeadingChange,
onTaskCheckedChange,
onTocChange,
baseUrl,
onImageClick,
useAlternativeBreaks,
lineOffset,
slideOptions
}) => {
const markdownBodyRef = useRef<HTMLDivElement>(null)
const tocAst = useRef<TocAst>()
const [trimmedContent, contentExceedsLimit] = useTrimmedContent(content)
const markdownIt = useMemo(
() =>
new BasicMarkdownItConfigurator({
onToc: (toc) => (tocAst.current = toc),
useAlternativeBreaks,
lineOffset,
headlineAnchors: false,
slideSections: true
}).buildConfiguredMarkdownIt(),
[lineOffset, useAlternativeBreaks]
)
const replacers = useComponentReplacers(onTaskCheckedChange, onImageClick, baseUrl, lineOffset)
const markdownReactDom = useConvertMarkdownToReactDom(
trimmedContent,
markdownIt,
replacers,
processRevealCommentNodes
)
useExtractFirstHeadline(markdownBodyRef, content, onFirstHeadingChange)
useOnRefChange(tocAst, onTocChange)
useReveal(content, slideOptions)
return (
<Fragment>
<DocumentLengthLimitReachedAlert show={contentExceedsLimit} />
<div className={'reveal'}>
<div ref={markdownBodyRef} className={`${className ?? ''} slides`}>
{markdownReactDom}
</div>
</div>
</Fragment>
)
}
export default SlideshowMarkdownRenderer

View file

@ -0,0 +1,14 @@
/*!
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
@import "../../../node_modules/reveal.js/css/reveal";
@import "../../../node_modules/reveal.js/dist/theme/fonts/league-gothic/league-gothic.css";
@import "slide-theme";
//Fix to make transitions work with bootstrap
.reveal [hidden] {
display: block !important;
}

View file

@ -13,8 +13,3 @@ export interface LineMarkerPosition {
line: number
position: number
}
export interface AdditionalMarkdownRendererProps {
className?: string
content: string
}

View file

@ -5,5 +5,7 @@
*/
.button-inside {
margin-top: -31px;
position: absolute;
bottom: 10px;
right: 10px;
}