mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-14 15:14:56 -04:00
Replace custom gist implementation with github rendering (#1436)
* Replace custom gist implementation with github rendering Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
64443a3b64
commit
dee494386a
4 changed files with 143 additions and 60 deletions
|
@ -91,6 +91,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||||
- Change editor font to "Fira Code"
|
- Change editor font to "Fira Code"
|
||||||
- Note tags can be set as yaml-array in frontmatter.
|
- Note tags can be set as yaml-array in frontmatter.
|
||||||
- If only one external login provider is configured, the sign-in button will directly link to it.
|
- If only one external login provider is configured, the sign-in button will directly link to it.
|
||||||
|
- Links in Gist-Frames work only if explicitly opened in new tabs.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,18 @@
|
||||||
filter: blur(3px);
|
filter: blur(3px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gist-resizer-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.gist-resizer {
|
||||||
|
display: flex;
|
||||||
|
width: 48px;
|
||||||
|
height: 5px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 90px;
|
||||||
|
cursor: row-resize;
|
||||||
|
box-shadow: black 0 0 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,77 +4,43 @@
|
||||||
SPDX-License-Identifier: AGPL-3.0-only
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
import React, { useCallback } from 'react'
|
||||||
import './gist-frame.scss'
|
import './gist-frame.scss'
|
||||||
|
import { useResizeGistFrame } from './use-resize-gist-frame'
|
||||||
|
|
||||||
export interface GistFrameProps {
|
export interface GistFrameProps {
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface resizeEvent {
|
/**
|
||||||
size: number
|
* This component renders a GitHub Gist by placing the gist URL in an {@link HTMLIFrameElement iframe}.
|
||||||
id: string
|
*
|
||||||
}
|
* @param id The id of the gist
|
||||||
|
*/
|
||||||
export const GistFrame: React.FC<GistFrameProps> = ({ id }) => {
|
export const GistFrame: React.FC<GistFrameProps> = ({ id }) => {
|
||||||
const iframeHtml = useMemo(() => {
|
const [frameHeight, onStartResizing] = useResizeGistFrame(150)
|
||||||
return `
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<base target="_parent">
|
|
||||||
<title>gist</title>
|
|
||||||
<style>
|
|
||||||
* { font-size:12px; }
|
|
||||||
body{ overflow:hidden; margin: 0;}
|
|
||||||
</style>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function doLoad() {
|
|
||||||
window.parent.postMessage({eventType: 'gistResize', size: document.body.scrollHeight, id: '${id}'}, '*')
|
|
||||||
tweakLinks();
|
|
||||||
}
|
|
||||||
function tweakLinks() {
|
|
||||||
document.querySelectorAll(".gist-meta > a").forEach((link) => {
|
|
||||||
link.rel="noopener noreferer"
|
|
||||||
link.target="_blank"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body onload="doLoad()">
|
|
||||||
<script type="text/javascript" src="https://gist.github.com/${id}.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>`
|
|
||||||
}, [id])
|
|
||||||
|
|
||||||
const [frameHeight, setFrameHeight] = useState(0)
|
const onStart = useCallback(
|
||||||
|
(event) => {
|
||||||
const sizeMessage = useCallback(
|
onStartResizing(event)
|
||||||
(message: MessageEvent) => {
|
|
||||||
const data = message.data as resizeEvent
|
|
||||||
if (data.id !== id) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setFrameHeight(data.size)
|
|
||||||
},
|
},
|
||||||
[id]
|
[onStartResizing]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
window.addEventListener('message', sizeMessage)
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('message', sizeMessage)
|
|
||||||
}
|
|
||||||
}, [sizeMessage])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<span>
|
||||||
<iframe
|
<iframe
|
||||||
sandbox='allow-scripts allow-top-navigation-by-user-activation allow-popups'
|
sandbox=''
|
||||||
data-cy={'gh-gist'}
|
data-cy={'gh-gist'}
|
||||||
width='100%'
|
width='100%'
|
||||||
height={`${frameHeight}px`}
|
height={`${frameHeight}px`}
|
||||||
frameBorder='0'
|
frameBorder='0'
|
||||||
title={`gist ${id}`}
|
title={`gist ${id}`}
|
||||||
src={`data:text/html;base64,${btoa(iframeHtml)}`}
|
src={`https://gist.github.com/${id}.pibb`}
|
||||||
/>
|
/>
|
||||||
|
<span className={'gist-resizer-row'}>
|
||||||
|
<span className={'gist-resizer'} onMouseDown={onStart} onTouchStart={onStart} />
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the left mouse button is pressed in the given event
|
||||||
|
*
|
||||||
|
* @param mouseEvent the mouse event that should be checked
|
||||||
|
* @return {@code true} if the left mouse button is pressed. {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
const isLeftMouseButtonPressed = (mouseEvent: MouseEvent): boolean => {
|
||||||
|
return mouseEvent.buttons === 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the absolute vertical position of the mouse or touch point from the event.
|
||||||
|
*
|
||||||
|
* @param moveEvent the vertical position of the mouse pointer or the first touch pointer.
|
||||||
|
* @return the extracted vertical position.
|
||||||
|
*/
|
||||||
|
const extractVerticalPointerPosition = (moveEvent: MouseEvent | TouchEvent): number => {
|
||||||
|
if (isMouseEvent(moveEvent)) {
|
||||||
|
return moveEvent.pageY
|
||||||
|
} else {
|
||||||
|
return moveEvent.touches[0]?.pageY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given {@link Event} is a {@link MouseEvent}
|
||||||
|
* @param event the event to check
|
||||||
|
* @return {@code true} if the given event is a {@link MouseEvent}
|
||||||
|
*/
|
||||||
|
const isMouseEvent = (event: Event): event is MouseEvent => {
|
||||||
|
return (event as MouseEvent).buttons !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PointerEvent = MouseEvent | TouchEvent
|
||||||
|
export type PointerEventHandler = (event: PointerEvent) => void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides logic for resizing a {@link GistFrame gist frame} by dragging an element.
|
||||||
|
*
|
||||||
|
* @param initialFrameHeight The initial size for the frame
|
||||||
|
* @return An array containing the current frame height and function to start the resizing
|
||||||
|
*/
|
||||||
|
export const useResizeGistFrame = (initialFrameHeight: number): [number, PointerEventHandler] => {
|
||||||
|
const [frameHeight, setFrameHeight] = useState(initialFrameHeight)
|
||||||
|
const lastYPosition = useRef<number | undefined>(undefined)
|
||||||
|
|
||||||
|
const onMove = useCallback((moveEvent: MouseEvent | TouchEvent) => {
|
||||||
|
if (lastYPosition.current === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isMouseEvent(moveEvent) && !isLeftMouseButtonPressed(moveEvent)) {
|
||||||
|
lastYPosition.current = undefined
|
||||||
|
moveEvent.preventDefault()
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPointerPosition = extractVerticalPointerPosition(moveEvent)
|
||||||
|
const deltaPointerPosition = currentPointerPosition - lastYPosition.current
|
||||||
|
lastYPosition.current = currentPointerPosition
|
||||||
|
setFrameHeight((oldFrameHeight) => Math.max(0, oldFrameHeight + deltaPointerPosition))
|
||||||
|
moveEvent.preventDefault()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const onStartResizing: PointerEventHandler = useCallback((event) => {
|
||||||
|
lastYPosition.current = extractVerticalPointerPosition(event)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const onStopResizing = useCallback(() => {
|
||||||
|
if (lastYPosition.current !== undefined) {
|
||||||
|
lastYPosition.current = undefined
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const moveHandler = onMove
|
||||||
|
const stopResizeHandler = onStopResizing
|
||||||
|
window.addEventListener('touchmove', moveHandler)
|
||||||
|
window.addEventListener('mousemove', moveHandler)
|
||||||
|
window.addEventListener('touchcancel', stopResizeHandler)
|
||||||
|
window.addEventListener('touchend', stopResizeHandler)
|
||||||
|
window.addEventListener('mouseup', stopResizeHandler)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('touchmove', moveHandler)
|
||||||
|
window.removeEventListener('mousemove', moveHandler)
|
||||||
|
window.removeEventListener('touchcancel', stopResizeHandler)
|
||||||
|
window.removeEventListener('touchend', stopResizeHandler)
|
||||||
|
window.removeEventListener('mouseup', stopResizeHandler)
|
||||||
|
}
|
||||||
|
}, [onMove, onStopResizing])
|
||||||
|
|
||||||
|
return [frameHeight, onStartResizing]
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue