mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-21 10:45:20 -04:00
Switch the base framework from Create React App to Next.JS
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
a979b6ffdd
commit
77a60c6c48
361 changed files with 5130 additions and 9605 deletions
|
@ -6,7 +6,6 @@
|
|||
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { useConvertMarkdownToReactDom } from './hooks/use-convert-markdown-to-react-dom'
|
||||
import './markdown-renderer.scss'
|
||||
import type { LineMarkerPosition } from './markdown-extension/linemarker/types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type { LineMarkers } from './markdown-extension/linemarker/add-line-marker-markdown-it-plugin'
|
||||
|
@ -17,6 +16,7 @@ import { useOnRefChange } from './hooks/use-on-ref-change'
|
|||
import type { CommonMarkdownRendererProps } from './common-markdown-renderer-props'
|
||||
import { useMarkdownExtensions } from './hooks/use-markdown-extensions'
|
||||
import { HeadlineAnchorsMarkdownExtension } from './markdown-extension/headline-anchors-markdown-extension'
|
||||
import { cypressId } from '../../utils/cypress-attribute'
|
||||
|
||||
export interface DocumentMarkdownRendererProps extends CommonMarkdownRendererProps {
|
||||
onLineMarkerPositionChanged?: (lineMarkerPosition: LineMarkerPosition[]) => void
|
||||
|
@ -65,9 +65,11 @@ export const DocumentMarkdownRenderer: React.FC<DocumentMarkdownRendererProps> =
|
|||
useOnRefChange(tocAst, onTocChange)
|
||||
|
||||
return (
|
||||
<div ref={outerContainerRef} className={'position-relative'}>
|
||||
<div ref={outerContainerRef} className={`position-relative`}>
|
||||
<div
|
||||
{...cypressId('markdown-body')}
|
||||
ref={markdownBodyRef}
|
||||
data-word-count-target={true}
|
||||
className={`${className ?? ''} markdown-body w-100 d-flex flex-column align-items-center`}>
|
||||
{markdownReactDom}
|
||||
</div>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,8 @@ import type { MutableRefObject } from 'react'
|
|||
import { useMemo } from 'react'
|
||||
import { TableOfContentsMarkdownExtension } from '../markdown-extension/table-of-contents-markdown-extension'
|
||||
import { VegaLiteMarkdownExtension } from '../markdown-extension/vega-lite/vega-lite-markdown-extension'
|
||||
import { MarkmapMarkdownExtension } from '../markdown-extension/markmap/markmap-markdown-extension'
|
||||
//TODO: fix dependency issues in markmap
|
||||
//import { MarkmapMarkdownExtension } from '../markdown-extension/markmap/markmap-markdown-extension'
|
||||
import { LinemarkerMarkdownExtension } from '../markdown-extension/linemarker/linemarker-markdown-extension'
|
||||
import { GistMarkdownExtension } from '../markdown-extension/gist/gist-markdown-extension'
|
||||
import { YoutubeMarkdownExtension } from '../markdown-extension/youtube/youtube-markdown-extension'
|
||||
|
@ -71,7 +72,7 @@ export const useMarkdownExtensions = (
|
|||
new TableOfContentsMarkdownExtension(onTocChange),
|
||||
...additionalExtensions,
|
||||
new VegaLiteMarkdownExtension(),
|
||||
new MarkmapMarkdownExtension(),
|
||||
// new MarkmapMarkdownExtension(),
|
||||
new LinemarkerMarkdownExtension(
|
||||
lineOffset,
|
||||
currentLineMarkers ? (lineMarkers) => (currentLineMarkers.current = lineMarkers) : undefined
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import Reveal from 'reveal.js'
|
||||
import type Reveal from 'reveal.js'
|
||||
import { Logger } from '../../../utils/logger'
|
||||
import type { SlideOptions } from '../../../redux/note-details/types/slide-show-options'
|
||||
|
||||
|
@ -38,25 +38,32 @@ export const useReveal = (markdownContentLines: string[], slideOptions?: SlideOp
|
|||
}
|
||||
setRevealStatus(REVEAL_STATUS.INITIALISING)
|
||||
log.debug('Initialize with slide options', slideOptions)
|
||||
const reveal = new Reveal({})
|
||||
reveal
|
||||
.initialize()
|
||||
.then(() => {
|
||||
reveal.layout()
|
||||
reveal.slide(0, 0, 0)
|
||||
reveal.addEventListener('slidechanged', (event) => {
|
||||
currentSlideState.current = {
|
||||
indexHorizontal: event.indexh,
|
||||
indexVertical: event.indexv ?? 0
|
||||
} as SlideState
|
||||
})
|
||||
|
||||
setDeck(reveal)
|
||||
setRevealStatus(REVEAL_STATUS.INITIALISED)
|
||||
log.debug('Initialisation finished')
|
||||
import(/* webpackChunkName: "reveal" */ 'reveal.js')
|
||||
.then((revealImport) => {
|
||||
const reveal = new revealImport.default({})
|
||||
reveal
|
||||
.initialize()
|
||||
.then(() => {
|
||||
reveal.layout()
|
||||
reveal.slide(0, 0, 0)
|
||||
reveal.addEventListener('slidechanged', (event) => {
|
||||
currentSlideState.current = {
|
||||
indexHorizontal: event.indexh,
|
||||
indexVertical: event.indexv ?? 0
|
||||
} as SlideState
|
||||
})
|
||||
|
||||
setDeck(reveal)
|
||||
setRevealStatus(REVEAL_STATUS.INITIALISED)
|
||||
log.debug('Initialisation finished')
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
log.error('Error while initializing reveal.js', error)
|
||||
})
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
log.error('Error while initializing reveal.js', error)
|
||||
log.error('Error while loading reveal.js', error)
|
||||
})
|
||||
}, [revealStatus, slideOptions])
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
import './abc.scss'
|
||||
import styles from './abc.module.scss'
|
||||
import { Logger } from '../../../../utils/logger'
|
||||
import type { CodeProps } from '../../replace-components/code-block-component-replacer'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
|
@ -29,5 +29,11 @@ export const AbcFrame: React.FC<CodeProps> = ({ code }) => {
|
|||
})
|
||||
}, [code])
|
||||
|
||||
return <div ref={container} className={'abcjs-score bg-white text-black svg-container'} {...cypressId('abcjs')} />
|
||||
return (
|
||||
<div
|
||||
ref={container}
|
||||
className={`${styles['abcjs-score']} bg-white text-black svg-container`}
|
||||
{...cypressId('abcjs')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*!
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
@ -6,9 +6,9 @@
|
|||
|
||||
|
||||
.abcjs-score {
|
||||
@import "../../../../style/variables";
|
||||
@import "../../../../../global-styles/variables";
|
||||
|
||||
.markdown-body & {
|
||||
:global(.markdown-body) & {
|
||||
overflow-x: auto !important;
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { NativeRenderer, NodeReplacement, SubNodeTransform } from '../../replace-components/component-replacer'
|
||||
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||
import type { Element } from 'domhandler'
|
||||
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
|
||||
import { isText } from 'domhandler'
|
||||
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
|
||||
import { cssColor } from './blockquote-border-color-node-preprocessor'
|
||||
import Optional from 'optional-js'
|
||||
import type { Text } from 'domhandler/lib/node'
|
||||
|
@ -21,18 +21,19 @@ import { BlockquoteExtraTagMarkdownExtension } from './blockquote-extra-tag-mark
|
|||
* @see BlockquoteTagMarkdownItPlugin
|
||||
*/
|
||||
export class BlockquoteColorExtraTagReplacer extends ComponentReplacer {
|
||||
replace(element: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
||||
replace(element: Element): NodeReplacement {
|
||||
if (
|
||||
element.tagName === BlockquoteExtraTagMarkdownExtension.tagName &&
|
||||
element.attribs?.['data-label'] === 'color' &&
|
||||
element.children !== undefined
|
||||
) {
|
||||
let index = 0
|
||||
return Optional.ofNullable(element.children[0])
|
||||
.filter(isText)
|
||||
.map((child) => (child as Text).data)
|
||||
.filter((content) => cssColor.test(content))
|
||||
.map<NodeReplacement>((color) => (
|
||||
<span className={'blockquote-extra'} style={{ color: color }}>
|
||||
<span className={'blockquote-extra'} key={(index += 1)} style={{ color: color }}>
|
||||
<ForkAwesomeIcon key='icon' className={'mx-1'} icon={'tag'} />
|
||||
</span>
|
||||
))
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { NativeRenderer, NodeReplacement, SubNodeTransform } from '../../replace-components/component-replacer'
|
||||
import type { NodeReplacement, SubNodeTransform } from '../../replace-components/component-replacer'
|
||||
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||
import type { Element } from 'domhandler'
|
||||
import type { ForkAwesomeIconProps } from '../../../common/fork-awesome/fork-awesome-icon'
|
||||
|
@ -22,7 +22,7 @@ import { BlockquoteExtraTagMarkdownExtension } from './blockquote-extra-tag-mark
|
|||
* @see ColoredBlockquoteNodePreprocessor
|
||||
*/
|
||||
export class BlockquoteExtraTagReplacer extends ComponentReplacer {
|
||||
replace(element: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
||||
replace(element: Element, subNodeTransform: SubNodeTransform): NodeReplacement {
|
||||
if (element.tagName !== BlockquoteExtraTagMarkdownExtension.tagName || !element.attribs) {
|
||||
return DO_NOT_REPLACE
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React, { useCallback } from 'react'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
import './gist-frame.scss'
|
||||
import styles from './gist-frame.module.scss'
|
||||
import { useResizeGistFrame } from './use-resize-gist-frame'
|
||||
import type { IdProps } from '../../replace-components/custom-tag-with-id-component-replacer'
|
||||
import { ClickShield } from '../../replace-components/click-shield/click-shield'
|
||||
|
@ -41,8 +41,8 @@ export const GistFrame: React.FC<IdProps> = ({ id }) => {
|
|||
title={`gist ${id}`}
|
||||
src={`https://gist.github.com/${id}.pibb`}
|
||||
/>
|
||||
<span className={'gist-resizer-row'}>
|
||||
<span className={'gist-resizer'} onMouseDown={onStart} onTouchStart={onStart} />
|
||||
<span className={styles['gist-resizer-row']}>
|
||||
<span className={styles['gist-resizer']} onMouseDown={onStart} onTouchStart={onStart} />
|
||||
</span>
|
||||
</ClickShield>
|
||||
)
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { Alert } from 'react-bootstrap'
|
||||
import { ShowIf } from '../../../common/show-if/show-if'
|
||||
import { useFrontendBaseUrl } from '../../../../hooks/common/use-frontend-base-url'
|
||||
import { Logger } from '../../../../utils/logger'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
import type { CodeProps } from '../../replace-components/code-block-component-replacer'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const log = new Logger('GraphvizFrame')
|
||||
|
||||
|
@ -27,7 +27,7 @@ export const GraphvizFrame: React.FC<CodeProps> = ({ code }) => {
|
|||
container.current.querySelectorAll('svg').forEach((child) => child.remove())
|
||||
}, [])
|
||||
|
||||
const frontendBaseUrl = useFrontendBaseUrl()
|
||||
const { basePath } = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (!container.current) {
|
||||
|
@ -37,7 +37,7 @@ export const GraphvizFrame: React.FC<CodeProps> = ({ code }) => {
|
|||
|
||||
import(/* webpackChunkName: "d3-graphviz" */ '@hpcc-js/wasm')
|
||||
.then((wasmPlugin) => {
|
||||
wasmPlugin.wasmFolder(`${frontendBaseUrl}/static/js`)
|
||||
wasmPlugin.wasmFolder(`${basePath}/_next/static/js`)
|
||||
})
|
||||
.then(() => import(/* webpackChunkName: "d3-graphviz" */ 'd3-graphviz'))
|
||||
.then((graphvizImport) => {
|
||||
|
@ -57,7 +57,7 @@ export const GraphvizFrame: React.FC<CodeProps> = ({ code }) => {
|
|||
.catch((error: Error) => {
|
||||
log.error('Error while loading graphviz', error)
|
||||
})
|
||||
}, [code, error, frontendBaseUrl, showError])
|
||||
}, [code, error, basePath, showError])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
|
|
@ -57,4 +57,8 @@ export class HighlightedCodeReplacer extends ComponentReplacer {
|
|||
/>
|
||||
)
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.lastLineNumber = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.code-highlighter {
|
||||
position: relative;
|
||||
|
||||
:global(code.hljs) {
|
||||
overflow-x: auto;
|
||||
background-color: rgba(27, 31, 35, .05);
|
||||
padding: 16px;
|
||||
display: grid !important;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
|
||||
:global(body.dark) & {
|
||||
background-color: rgb(27, 31, 35);
|
||||
}
|
||||
|
||||
.codeline {
|
||||
grid-column: 2;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.linenumber {
|
||||
grid-column: 1;
|
||||
position: relative;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
padding: 0 8px 0 0;
|
||||
min-width: 20px;
|
||||
box-sizing: content-box;
|
||||
color: #afafaf;
|
||||
border-right: 3px solid #6ce26c;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
align-items: flex-end;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.showGutter {
|
||||
.linenumber {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.codeline {
|
||||
margin: 0 0 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.wrapLines .codeline {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.code-highlighter {
|
||||
@import '../../../../../node_modules/highlight.js/styles/github';
|
||||
|
||||
body.dark & {
|
||||
@import '../../../../../node_modules/highlight.js/styles/github-dark';
|
||||
}
|
||||
|
||||
position: relative;
|
||||
|
||||
code.hljs {
|
||||
overflow-x: auto;
|
||||
background-color: rgba(27, 31, 35, .05);
|
||||
|
||||
body.dark & {
|
||||
background-color: rgb(27, 31, 35);
|
||||
}
|
||||
|
||||
body.dark &, & {
|
||||
padding: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr);
|
||||
|
||||
.codeline {
|
||||
grid-column: 2;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.linenumber {
|
||||
grid-column: 1;
|
||||
position: relative;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
padding: 0 8px 0 0;
|
||||
min-width: 20px;
|
||||
box-sizing: content-box;
|
||||
color: #afafaf;
|
||||
border-right: 3px solid #6ce26c;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
align-items: flex-end;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.showGutter {
|
||||
.linenumber {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.codeline {
|
||||
margin: 0 0 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.wrapLines .codeline {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,9 @@ import type { ReactElement } from 'react'
|
|||
import React, { Fragment, useEffect, useState } from 'react'
|
||||
import convertHtmlToReact from '@hedgedoc/html-to-react'
|
||||
import { CopyToClipboardButton } from '../../../common/copyable/copy-to-clipboard-button/copy-to-clipboard-button'
|
||||
import '../../utils/button-inside.scss'
|
||||
import './highlighted-code.scss'
|
||||
import styles from './highlighted-code.module.scss'
|
||||
import { Logger } from '../../../../utils/logger'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
import { cypressAttribute, cypressId } from '../../../../utils/cypress-attribute'
|
||||
|
||||
const log = new Logger('HighlightedCode')
|
||||
|
||||
|
@ -54,8 +53,12 @@ export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language
|
|||
: escapeHtml(code)
|
||||
const replacedDom = replaceCode(unreplacedCode).map((line, index) => (
|
||||
<Fragment key={index}>
|
||||
<span className={'linenumber'}>{(startLineNumber || 1) + index}</span>
|
||||
<div className={'codeline'}>{line}</div>
|
||||
<span {...cypressId('linenumber')} className={styles['linenumber']}>
|
||||
{(startLineNumber || 1) + index}
|
||||
</span>
|
||||
<div {...cypressId('codeline')} className={styles['codeline']}>
|
||||
{line}
|
||||
</div>
|
||||
</Fragment>
|
||||
))
|
||||
setDom(replacedDom)
|
||||
|
@ -65,9 +68,15 @@ export const HighlightedCode: React.FC<HighlightedCodeProps> = ({ code, language
|
|||
})
|
||||
}, [code, language, startLineNumber])
|
||||
|
||||
const showGutter = startLineNumber !== undefined
|
||||
|
||||
return (
|
||||
<div className={'code-highlighter'} {...cypressId('highlighted-code-block')}>
|
||||
<code className={`hljs ${startLineNumber !== undefined ? 'showGutter' : ''} ${wrapLines ? 'wrapLines' : ''}`}>
|
||||
<div className={styles['code-highlighter']} {...cypressId('highlighted-code-block')}>
|
||||
<code
|
||||
{...cypressId('code-highlighter')}
|
||||
{...cypressAttribute('showgutter', showGutter ? 'true' : 'false')}
|
||||
{...cypressAttribute('wraplines', wrapLines ? 'true' : 'false')}
|
||||
className={`hljs ${showGutter ? styles['showGutter'] : ''} ${wrapLines ? styles['wrapLines'] : ''}`}>
|
||||
{dom}
|
||||
</code>
|
||||
<div className={'text-right button-inside'}>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { NativeRenderer, NodeReplacement, SubNodeTransform } from '../../replace-components/component-replacer'
|
||||
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
||||
import type { Element } from 'domhandler'
|
||||
import { ImagePlaceholder } from './image-placeholder'
|
||||
|
@ -24,7 +24,7 @@ export class ImagePlaceholderReplacer extends ComponentReplacer {
|
|||
this.countPerSourceLine = new Map<number, number>()
|
||||
}
|
||||
|
||||
replace(node: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
||||
replace(node: Element): NodeReplacement {
|
||||
if (node.name === 'img' && node.attribs && node.attribs.src === ImagePlaceholderMarkdownExtension.PLACEHOLDER_URL) {
|
||||
const lineIndex = Number(node.attribs['data-line'])
|
||||
const indexInLine = this.countPerSourceLine.get(lineIndex) ?? 0
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
/*!
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.image-drop {
|
||||
@import "../../../../style/variables.light.scss";
|
||||
@import "../../../../../global-styles/variables.light.scss";
|
||||
border: 3px dashed $dark;
|
||||
|
||||
body.dark & {
|
||||
@import "../../../../style/variables.dark.scss";
|
||||
:global(body.dark) & {
|
||||
@import "../../../../../global-styles/variables.dark.scss";
|
||||
border-color: $dark;
|
||||
}
|
||||
|
|
@ -8,10 +8,11 @@ import React, { useCallback, useMemo, useRef, useState } from 'react'
|
|||
import { Button } from 'react-bootstrap'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { ForkAwesomeIcon } from '../../../common/fork-awesome/fork-awesome-icon'
|
||||
import './image-placeholder.scss'
|
||||
import styles from './image-placeholder.module.scss'
|
||||
import { acceptedMimeTypes } from '../../../common/upload-image-mimetypes'
|
||||
import { useOnImageUpload } from './hooks/use-on-image-upload'
|
||||
import { usePlaceholderSizeStyle } from './hooks/use-placeholder-size-style'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
|
||||
export interface PlaceholderImageFrameProps {
|
||||
alt?: string
|
||||
|
@ -83,7 +84,8 @@ export const ImagePlaceholder: React.FC<PlaceholderImageFrameProps> = ({
|
|||
|
||||
return (
|
||||
<span
|
||||
className={`image-drop d-inline-flex flex-column align-items-center ${containerDragClasses} p-1`}
|
||||
{...cypressId('image-placeholder-image-drop')}
|
||||
className={`${styles['image-drop']} d-inline-flex flex-column align-items-center ${containerDragClasses} p-1`}
|
||||
style={containerStyle}
|
||||
onDrop={onDropHandler}
|
||||
onDragOver={onDragOverHandler}
|
||||
|
@ -100,7 +102,7 @@ export const ImagePlaceholder: React.FC<PlaceholderImageFrameProps> = ({
|
|||
<span className='my-2'>
|
||||
<Trans i18nKey={'editor.embeddings.placeholderImage.placeholderText'} />
|
||||
</span>
|
||||
<span className={'altText'}>{alt ?? title ?? ''}</span>
|
||||
<span className={styles['altText']}>{alt ?? title ?? ''}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button size={'sm'} variant={'primary'} onClick={uploadButtonClicked}>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import './lightbox.scss'
|
||||
import styles from './lightbox.module.scss'
|
||||
import { ProxyImageFrame } from './proxy-image-frame'
|
||||
import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
|
||||
import { CommonModal } from '../../../common/modals/common-modal'
|
||||
|
@ -23,7 +23,7 @@ export const ImageLightboxModal: React.FC<ImageLightboxModalProps> = ({ show, on
|
|||
show={show && !!src}
|
||||
onHide={onHide}
|
||||
showCloseButton={true}
|
||||
additionalClasses={'lightbox'}
|
||||
additionalClasses={styles.lightbox}
|
||||
title={alt ?? title ?? ''}
|
||||
titleIsI18nKey={false}>
|
||||
<ProxyImageFrame alt={alt} src={src} title={title} className={'w-100 cursor-zoom-out'} onClick={onHide} />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*!
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
@ -24,5 +24,7 @@ export const ProxyImageFrame: React.FC<React.ImgHTMLAttributes<HTMLImageElement>
|
|||
.catch((err) => log.error(err))
|
||||
}, [imageProxyEnabled, src])
|
||||
|
||||
// The next image processor works with a whitelist of origins. Therefore we can't use it for general images.
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
return <img src={imageProxyEnabled ? imageUrl : src ?? ''} title={title ?? alt ?? ''} alt={alt} {...props} />
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import type { Element } from 'domhandler'
|
|||
import { isTag } from 'domhandler'
|
||||
import React from 'react'
|
||||
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||
import './katex.scss'
|
||||
import 'katex/dist/katex.min.css'
|
||||
import { KatexMarkdownExtension } from './katex-markdown-extension'
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@import '../../../../../node_modules/katex/dist/katex.min.css';
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { Element } from 'domhandler'
|
||||
|
|
|
@ -9,10 +9,12 @@ import type { NodeProcessor } from '../node-preprocessors/node-processor'
|
|||
import type { ComponentReplacer } from '../replace-components/component-replacer'
|
||||
|
||||
export abstract class MarkdownExtension {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public configureMarkdownIt(markdownIt: MarkdownIt): void {
|
||||
return
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
public configureMarkdownItPost(markdownIt: MarkdownIt): void {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { LockButton } from '../../../common/lock-button/lock-button'
|
||||
import '../../utils/button-inside.scss'
|
||||
import { Logger } from '../../../../utils/logger'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
import type { CodeProps } from '../../replace-components/code-block-component-replacer'
|
||||
|
|
|
@ -8,9 +8,10 @@ import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react
|
|||
import { Alert } from 'react-bootstrap'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { ShowIf } from '../../../common/show-if/show-if'
|
||||
import './mermaid.scss'
|
||||
import styles from './mermaid.module.scss'
|
||||
import { Logger } from '../../../../utils/logger'
|
||||
import type { CodeProps } from '../../replace-components/code-block-component-replacer'
|
||||
import { cypressId } from '../../../../utils/cypress-attribute'
|
||||
|
||||
const log = new Logger('MermaidChart')
|
||||
|
||||
|
@ -78,7 +79,11 @@ export const MermaidChart: React.FC<CodeProps> = ({ code }) => {
|
|||
<ShowIf condition={!!error}>
|
||||
<Alert variant={'warning'}>{error}</Alert>
|
||||
</ShowIf>
|
||||
<div className={'text-center mermaid text-black'} ref={diagramContainer} />
|
||||
<div
|
||||
{...cypressId('mermaid-frame')}
|
||||
className={`text-center ${styles['mermaid']} text-black`}
|
||||
ref={diagramContainer}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { NativeRenderer, NodeReplacement, SubNodeTransform } from '../../replace-components/component-replacer'
|
||||
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||
import { ComponentReplacer, DO_NOT_REPLACE } from '../../replace-components/component-replacer'
|
||||
import { PlantumlNotConfiguredAlert } from './plantuml-not-configured-alert'
|
||||
import type { Element } from 'domhandler'
|
||||
|
||||
export class PlantumlNotConfiguredComponentReplacer extends ComponentReplacer {
|
||||
replace(node: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
||||
replace(node: Element): NodeReplacement {
|
||||
return node.tagName === 'plantuml-not-configured' ? <PlantumlNotConfiguredAlert /> : DO_NOT_REPLACE
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ const processCommentNode = (node: DataNode): void => {
|
|||
return
|
||||
}
|
||||
|
||||
for (const dataAttribute of regexResult[2].matchAll(dataAttributesSyntax)) {
|
||||
for (const dataAttribute of [...regexResult[2].matchAll(dataAttributesSyntax)]) {
|
||||
const attributeName = dataAttribute[1]
|
||||
const attributeValue = dataAttribute[2] ?? dataAttribute[3]
|
||||
if (attributeValue) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { NativeRenderer, NodeReplacement, SubNodeTransform } from '../../replace-components/component-replacer'
|
||||
import type { NodeReplacement } from '../../replace-components/component-replacer'
|
||||
import { ComponentReplacer } from '../../replace-components/component-replacer'
|
||||
import type { Element } from 'domhandler'
|
||||
import { UploadIndicatingFrame } from './upload-indicating-frame'
|
||||
|
@ -15,7 +15,7 @@ const uploadIdRegex = /^upload-(.+)$/
|
|||
* Replaces an image tag whose url is an upload-id with the {@link UploadIndicatingFrame upload indicating frame}.
|
||||
*/
|
||||
export class UploadIndicatingImageFrameReplacer extends ComponentReplacer {
|
||||
replace(node: Element, subNodeTransform: SubNodeTransform, nativeRenderer: NativeRenderer): NodeReplacement {
|
||||
replace(node: Element): NodeReplacement {
|
||||
if (node.name === 'img' && uploadIdRegex.test(node.attribs.src)) {
|
||||
return <UploadIndicatingFrame width={node.attribs.width} height={node.attribs.height} />
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React, { useCallback } from 'react'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@import './github-markdown';
|
||||
|
||||
.markdown-body {
|
||||
position: relative;
|
||||
font-family: 'Source Sans Pro', "Twemoji", sans-serif;
|
||||
word-break: break-word;
|
||||
|
||||
.svg-container {
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
|
||||
svg {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.alert > p, .alert > ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
// This is necessary since we need to set this for all DOM Element that could be children of .markdown-body and since we support all of HTML that would literally be everything
|
||||
& > * {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
a.heading-anchor {
|
||||
font-size: 0.75em;
|
||||
margin-top: 0.25em;
|
||||
opacity: 0.3;
|
||||
transition: opacity 0.1s;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blockquote .blockquote-extra {
|
||||
font-size: 0.85em;
|
||||
margin-inline-start: 0.5em;
|
||||
|
||||
&:first-of-type {
|
||||
&::before {
|
||||
content: '\2014 \00A0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: visible;
|
||||
|
||||
code {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -44,12 +44,12 @@
|
|||
min-height: 300px;
|
||||
width: 100%;
|
||||
|
||||
body.dark &{
|
||||
@import "../../../../style/variables.dark";
|
||||
:global(body.dark) &{
|
||||
@import "../../../../../global-styles/variables.dark";
|
||||
box-shadow: inset fade-out($black, 0.5) 0 0 20px;
|
||||
}
|
||||
|
||||
@import "../../../../style/variables.light";
|
||||
@import "../../../../../global-styles/variables.light";
|
||||
box-shadow: inset fade-out($black, 0.5) 0 0 20px;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import type { IconName } from '../../../common/fork-awesome/types'
|
||||
import { ShowIf } from '../../../common/show-if/show-if'
|
||||
import './click-shield.scss'
|
||||
import styles from './click-shield.module.scss'
|
||||
import { Logger } from '../../../../utils/logger'
|
||||
import type { Property } from 'csstype'
|
||||
import type { PropsWithDataCypressId } from '../../../../utils/cypress-attribute'
|
||||
|
@ -103,10 +103,10 @@ export const ClickShield: React.FC<ClickShieldProps> = ({
|
|||
<span className={containerClassName} {...cypressId(props['data-cypress-id'])}>
|
||||
<ShowIf condition={showChildren}>{children}</ShowIf>
|
||||
<ShowIf condition={!showChildren}>
|
||||
<span className={`click-shield embed-responsive embed-responsive-16by9`} onClick={doShowChildren}>
|
||||
<span className={`${styles['click-shield']} embed-responsive embed-responsive-16by9`} onClick={doShowChildren}>
|
||||
{previewBackground}
|
||||
<span className={`preview-hover text-center`}>
|
||||
<span className={'preview-hover-text'}>
|
||||
<span className={`${styles['preview-hover']} text-center`}>
|
||||
<span className={`${styles['preview-hover-text']}`}>
|
||||
<Trans i18nKey={'renderer.clickShield.previewHoverText'} values={hoverTextTranslationValues} />
|
||||
</span>
|
||||
<br />
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*!
|
||||
* 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";
|
||||
// ---------------------------------------------
|
|
@ -6,12 +6,10 @@
|
|||
|
||||
import React, { useEffect, useMemo, useRef } from 'react'
|
||||
import { useConvertMarkdownToReactDom } from './hooks/use-convert-markdown-to-react-dom'
|
||||
import './markdown-renderer.scss'
|
||||
import { useExtractFirstHeadline } from './hooks/use-extract-first-headline'
|
||||
import type { TocAst } from 'markdown-it-toc-done-right'
|
||||
import { useOnRefChange } from './hooks/use-on-ref-change'
|
||||
import { REVEAL_STATUS, useReveal } from './hooks/use-reveal'
|
||||
import './slideshow.scss'
|
||||
import type { ScrollProps } from '../editor-page/synced-scroll/scroll-props'
|
||||
import type { CommonMarkdownRendererProps } from './common-markdown-renderer-props'
|
||||
import { LoadingSlide } from './loading-slide'
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
/*!
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@import "../../../node_modules/reveal.js/dist/reveal.css";
|
||||
@import "../../../node_modules/reveal.js/dist/theme/fonts/league-gothic/league-gothic.css";
|
||||
@import "slide-theme";
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
.button-inside {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue