mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-28 16:50:59 -05:00
feat: add license frontmatter field for link header
This commit adds the "license" frontmatter property which sets a link with the "license" relation in the head of the HTML page. Furthermore, this commit restructures the other head elements for a note altogether into a single component that can be used to inject all head elements at once. Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
parent
91e7056882
commit
cf34df21b7
11 changed files with 59 additions and 11 deletions
|
@ -8,7 +8,6 @@ import { useApplyDarkMode } from '../../hooks/common/use-apply-dark-mode'
|
||||||
import { updateNoteTitleByFirstHeading } from '../../redux/note-details/methods'
|
import { updateNoteTitleByFirstHeading } from '../../redux/note-details/methods'
|
||||||
import { Logger } from '../../utils/logger'
|
import { Logger } from '../../utils/logger'
|
||||||
import { MotdModal } from '../common/motd-modal/motd-modal'
|
import { MotdModal } from '../common/motd-modal/motd-modal'
|
||||||
import { NoteAndAppTitleHead } from '../layout/note-and-app-title-head'
|
|
||||||
import { CommunicatorImageLightbox } from '../markdown-renderer/extensions/image/communicator-image-lightbox'
|
import { CommunicatorImageLightbox } from '../markdown-renderer/extensions/image/communicator-image-lightbox'
|
||||||
import { ExtensionEventEmitterProvider } from '../markdown-renderer/hooks/use-extension-event-emitter'
|
import { ExtensionEventEmitterProvider } from '../markdown-renderer/hooks/use-extension-event-emitter'
|
||||||
import { AppBar, AppBarMode } from './app-bar/app-bar'
|
import { AppBar, AppBarMode } from './app-bar/app-bar'
|
||||||
|
@ -16,8 +15,8 @@ import { ChangeEditorContentContextProvider } from './change-content-context/cha
|
||||||
import { EditorDocumentRenderer } from './editor-document-renderer/editor-document-renderer'
|
import { EditorDocumentRenderer } from './editor-document-renderer/editor-document-renderer'
|
||||||
import { EditorPane } from './editor-pane/editor-pane'
|
import { EditorPane } from './editor-pane/editor-pane'
|
||||||
import { useComponentsFromAppExtensions } from './editor-pane/hooks/use-components-from-app-extensions'
|
import { useComponentsFromAppExtensions } from './editor-pane/hooks/use-components-from-app-extensions'
|
||||||
|
import { HeadMetaProperties } from './head-meta-properties/head-meta-properties'
|
||||||
import { useUpdateLocalHistoryEntry } from './hooks/use-update-local-history-entry'
|
import { useUpdateLocalHistoryEntry } from './hooks/use-update-local-history-entry'
|
||||||
import { OpengraphHead } from './opengraph-head/opengraph-head'
|
|
||||||
import { Sidebar } from './sidebar/sidebar'
|
import { Sidebar } from './sidebar/sidebar'
|
||||||
import { Splitter } from './splitter/splitter'
|
import { Splitter } from './splitter/splitter'
|
||||||
import type { DualScrollState, ScrollState } from './synced-scroll/scroll-props'
|
import type { DualScrollState, ScrollState } from './synced-scroll/scroll-props'
|
||||||
|
@ -128,8 +127,7 @@ export const EditorPageContent: React.FC = () => {
|
||||||
<ExtensionEventEmitterProvider>
|
<ExtensionEventEmitterProvider>
|
||||||
{editorExtensionComponents}
|
{editorExtensionComponents}
|
||||||
<CommunicatorImageLightbox />
|
<CommunicatorImageLightbox />
|
||||||
<NoteAndAppTitleHead />
|
<HeadMetaProperties />
|
||||||
<OpengraphHead />
|
|
||||||
<MotdModal />
|
<MotdModal />
|
||||||
<div className={'d-flex flex-column vh-100'}>
|
<div className={'d-flex flex-column vh-100'}>
|
||||||
<AppBar mode={AppBarMode.EDITOR} />
|
<AppBar mode={AppBarMode.EDITOR} />
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import { LicenseLinkHead } from './license-link-head'
|
||||||
|
import { NoteAndAppTitleHead } from './note-and-app-title-head'
|
||||||
|
import { OpengraphHead } from './opengraph-head'
|
||||||
|
import React, { Fragment } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders all HTML head tags that should be present for a note.
|
||||||
|
*/
|
||||||
|
export const HeadMetaProperties: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<NoteAndAppTitleHead />
|
||||||
|
<OpengraphHead />
|
||||||
|
<LicenseLinkHead />
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
import { useApplicationState } from '../../../hooks/common/use-application-state'
|
||||||
|
import Head from 'next/head'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the license link tag if a license is set in the frontmatter.
|
||||||
|
*/
|
||||||
|
export const LicenseLinkHead: React.FC = () => {
|
||||||
|
const license = useApplicationState((state) => state.noteDetails.frontmatter.license)
|
||||||
|
|
||||||
|
const optionalLinkElement = useMemo(() => {
|
||||||
|
if (!license || license.trim() === '') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <link rel={'license'} href={license} />
|
||||||
|
}, [license])
|
||||||
|
|
||||||
|
return <Head>{optionalLinkElement}</Head>
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
import { useAppTitle } from '../../hooks/common/use-app-title'
|
import { useAppTitle } from '../../../hooks/common/use-app-title'
|
||||||
import { useNoteTitle } from '../../hooks/common/use-note-title'
|
import { useNoteTitle } from '../../../hooks/common/use-note-title'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import React, { useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
import { NoteLoadingBoundary } from '../../components/common/note-loading-boundary/note-loading-boundary'
|
import { NoteLoadingBoundary } from '../../components/common/note-loading-boundary/note-loading-boundary'
|
||||||
|
import { HeadMetaProperties } from '../../components/editor-page/head-meta-properties/head-meta-properties'
|
||||||
import { EditorToRendererCommunicatorContextProvider } from '../../components/editor-page/render-context/editor-to-renderer-communicator-context-provider'
|
import { EditorToRendererCommunicatorContextProvider } from '../../components/editor-page/render-context/editor-to-renderer-communicator-context-provider'
|
||||||
import { NoteAndAppTitleHead } from '../../components/layout/note-and-app-title-head'
|
|
||||||
import { SlideShowPageContent } from '../../components/slide-show-page/slide-show-page-content'
|
import { SlideShowPageContent } from '../../components/slide-show-page/slide-show-page-content'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import React from 'react'
|
||||||
export const SlideShowPage: React.FC = () => {
|
export const SlideShowPage: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<NoteLoadingBoundary>
|
<NoteLoadingBoundary>
|
||||||
<NoteAndAppTitleHead />
|
<HeadMetaProperties />
|
||||||
<EditorToRendererCommunicatorContextProvider>
|
<EditorToRendererCommunicatorContextProvider>
|
||||||
<SlideShowPageContent />
|
<SlideShowPageContent />
|
||||||
</EditorToRendererCommunicatorContextProvider>
|
</EditorToRendererCommunicatorContextProvider>
|
||||||
|
|
|
@ -7,8 +7,8 @@ import { MotdModal } from '../../components/common/motd-modal/motd-modal'
|
||||||
import { NoteLoadingBoundary } from '../../components/common/note-loading-boundary/note-loading-boundary'
|
import { NoteLoadingBoundary } from '../../components/common/note-loading-boundary/note-loading-boundary'
|
||||||
import { DocumentReadOnlyPageContent } from '../../components/document-read-only-page/document-read-only-page-content'
|
import { DocumentReadOnlyPageContent } from '../../components/document-read-only-page/document-read-only-page-content'
|
||||||
import { AppBar, AppBarMode } from '../../components/editor-page/app-bar/app-bar'
|
import { AppBar, AppBarMode } from '../../components/editor-page/app-bar/app-bar'
|
||||||
|
import { HeadMetaProperties } from '../../components/editor-page/head-meta-properties/head-meta-properties'
|
||||||
import { EditorToRendererCommunicatorContextProvider } from '../../components/editor-page/render-context/editor-to-renderer-communicator-context-provider'
|
import { EditorToRendererCommunicatorContextProvider } from '../../components/editor-page/render-context/editor-to-renderer-communicator-context-provider'
|
||||||
import { NoteAndAppTitleHead } from '../../components/layout/note-and-app-title-head'
|
|
||||||
import { useApplyDarkMode } from '../../hooks/common/use-apply-dark-mode'
|
import { useApplyDarkMode } from '../../hooks/common/use-apply-dark-mode'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export const DocumentReadOnlyPage: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<EditorToRendererCommunicatorContextProvider>
|
<EditorToRendererCommunicatorContextProvider>
|
||||||
<NoteLoadingBoundary>
|
<NoteLoadingBoundary>
|
||||||
<NoteAndAppTitleHead />
|
<HeadMetaProperties />
|
||||||
<MotdModal />
|
<MotdModal />
|
||||||
<div className={'d-flex flex-column mvh-100 bg-light'}>
|
<div className={'d-flex flex-column mvh-100 bg-light'}>
|
||||||
<AppBar mode={AppBarMode.BASIC} />
|
<AppBar mode={AppBarMode.BASIC} />
|
||||||
|
|
|
@ -54,6 +54,7 @@ export const initialState: NoteDetails = {
|
||||||
newlinesAreBreaks: true,
|
newlinesAreBreaks: true,
|
||||||
GA: '',
|
GA: '',
|
||||||
disqus: '',
|
disqus: '',
|
||||||
|
license: '',
|
||||||
type: NoteType.DOCUMENT,
|
type: NoteType.DOCUMENT,
|
||||||
opengraph: {},
|
opengraph: {},
|
||||||
slideOptions: initialSlideOptions
|
slideOptions: initialSlideOptions
|
||||||
|
|
|
@ -48,6 +48,7 @@ const parseRawNoteFrontmatter = (rawData: RawNoteFrontmatter): NoteFrontmatter =
|
||||||
dir: parseTextDirection(rawData),
|
dir: parseTextDirection(rawData),
|
||||||
opengraph: parseOpenGraph(rawData),
|
opengraph: parseOpenGraph(rawData),
|
||||||
slideOptions: parseSlideOptions(rawData),
|
slideOptions: parseSlideOptions(rawData),
|
||||||
|
license: rawData.license ?? initialState.frontmatter.license,
|
||||||
tags
|
tags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ export interface RawNoteFrontmatter {
|
||||||
breaks: boolean | undefined
|
breaks: boolean | undefined
|
||||||
GA: string | undefined
|
GA: string | undefined
|
||||||
disqus: string | undefined
|
disqus: string | undefined
|
||||||
|
license: string | undefined
|
||||||
type: string | undefined
|
type: string | undefined
|
||||||
slideOptions: { [key: string]: string } | null
|
slideOptions: { [key: string]: string } | null
|
||||||
opengraph: { [key: string]: string } | null
|
opengraph: { [key: string]: string } | null
|
||||||
|
|
|
@ -42,6 +42,7 @@ export interface NoteFrontmatter {
|
||||||
newlinesAreBreaks: boolean
|
newlinesAreBreaks: boolean
|
||||||
GA: string
|
GA: string
|
||||||
disqus: string
|
disqus: string
|
||||||
|
license: string
|
||||||
type: NoteType
|
type: NoteType
|
||||||
opengraph: OpenGraph
|
opengraph: OpenGraph
|
||||||
slideOptions: SlideOptions
|
slideOptions: SlideOptions
|
||||||
|
|
Loading…
Reference in a new issue