mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-18 00:54:43 -04:00
fix: Move content into to frontend directory
Doing this BEFORE the merge prevents a lot of merge conflicts. Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
4e18ce38f3
commit
762a0a850e
1051 changed files with 0 additions and 35 deletions
21
frontend/src/hooks/common/use-app-title.ts
Normal file
21
frontend/src/hooks/common/use-app-title.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useMemo } from 'react'
|
||||
import { useApplicationState } from './use-application-state'
|
||||
|
||||
/**
|
||||
* Calculates the app title with branding if set.
|
||||
*
|
||||
* @return The app title with branding.
|
||||
*/
|
||||
export const useAppTitle = (): string => {
|
||||
const brandingName = useApplicationState((state) => state.config.branding.name)
|
||||
|
||||
return useMemo(() => {
|
||||
return 'HedgeDoc' + (brandingName ? ` @ ${brandingName}` : '')
|
||||
}, [brandingName])
|
||||
}
|
23
frontend/src/hooks/common/use-application-state.ts
Normal file
23
frontend/src/hooks/common/use-application-state.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useSelector } from 'react-redux'
|
||||
import equal from 'fast-deep-equal'
|
||||
import type { ApplicationState } from '../../redux/application-state'
|
||||
|
||||
/**
|
||||
* Accesses the global application state to retrieve information.
|
||||
*
|
||||
* @param selector A selector function that extracts the needed information from the state.
|
||||
* @param checkForEquality An optional custom equality function. If not provided then {@link equal equal from fast-deep-equal} will be used.
|
||||
* @return The requested information
|
||||
*/
|
||||
export const useApplicationState = <TSelected>(
|
||||
selector: (state: ApplicationState) => TSelected,
|
||||
checkForEquality?: (a: TSelected, b: TSelected) => boolean
|
||||
): TSelected => {
|
||||
return useSelector<ApplicationState, TSelected>(selector, checkForEquality ? checkForEquality : equal)
|
||||
}
|
52
frontend/src/hooks/common/use-apply-dark-mode.ts
Normal file
52
frontend/src/hooks/common/use-apply-dark-mode.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { useApplicationState } from './use-application-state'
|
||||
import { isClientSideRendering } from '../../utils/is-client-side-rendering'
|
||||
import { Logger } from '../../utils/logger'
|
||||
import useMediaQuery from '@restart/hooks/useMediaQuery'
|
||||
import { DarkModePreference } from '../../redux/dark-mode/types'
|
||||
|
||||
const logger = new Logger('useApplyDarkMode')
|
||||
|
||||
export const DARK_MODE_LOCAL_STORAGE_KEY = 'forcedDarkMode'
|
||||
|
||||
/**
|
||||
* Applies the `dark` css class to the body tag according to the dark mode state.
|
||||
*/
|
||||
export const useApplyDarkMode = (): void => {
|
||||
const preference = useApplicationState((state) => state.darkMode.darkModePreference)
|
||||
const isBrowserPreferringDark = useMediaQuery('(prefers-color-scheme: dark)')
|
||||
|
||||
useEffect(() => saveToLocalStorage(preference), [preference])
|
||||
useEffect(() => {
|
||||
if (preference === DarkModePreference.DARK || (preference === DarkModePreference.AUTO && isBrowserPreferringDark)) {
|
||||
window.document.body.classList.add('dark')
|
||||
} else {
|
||||
window.document.body.classList.remove('dark')
|
||||
}
|
||||
}, [isBrowserPreferringDark, preference])
|
||||
|
||||
useEffect(() => () => window.document.body.classList.remove('dark'), [])
|
||||
}
|
||||
|
||||
export const saveToLocalStorage = (preference: DarkModePreference): void => {
|
||||
if (!isClientSideRendering()) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (preference === DarkModePreference.DARK) {
|
||||
window.localStorage.setItem(DARK_MODE_LOCAL_STORAGE_KEY, 'dark')
|
||||
} else if (preference === DarkModePreference.LIGHT) {
|
||||
window.localStorage.setItem(DARK_MODE_LOCAL_STORAGE_KEY, 'light')
|
||||
} else if (preference === DarkModePreference.AUTO) {
|
||||
window.localStorage.removeItem(DARK_MODE_LOCAL_STORAGE_KEY)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Saving to local storage failed', error)
|
||||
}
|
||||
}
|
23
frontend/src/hooks/common/use-array-string-url-parameter.ts
Normal file
23
frontend/src/hooks/common/use-array-string-url-parameter.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
/**
|
||||
* Extracts the parameter from the router expected to be an array of values.
|
||||
*
|
||||
* @param parameter The parameter to extract
|
||||
* @return An array of values extracted from the router.
|
||||
*/
|
||||
export const useArrayStringUrlParameter = (parameter: string): string[] => {
|
||||
const router = useRouter()
|
||||
|
||||
return useMemo(() => {
|
||||
const value = router.query[parameter]
|
||||
return (typeof value === 'string' ? [value] : value) ?? []
|
||||
}, [parameter, router.query])
|
||||
}
|
33
frontend/src/hooks/common/use-base-url.tsx
Normal file
33
frontend/src/hooks/common/use-base-url.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useContext, useMemo } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { baseUrlContext } from '../../components/common/base-url/base-url-context-provider'
|
||||
|
||||
export enum ORIGIN {
|
||||
EDITOR,
|
||||
RENDERER,
|
||||
CURRENT_PAGE
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the base urls for the editor and the renderer.
|
||||
*/
|
||||
export const useBaseUrl = (origin = ORIGIN.CURRENT_PAGE): string => {
|
||||
const baseUrls = useContext(baseUrlContext)
|
||||
if (!baseUrls) {
|
||||
throw new Error('No base url context received. Did you forget to use the provider component?')
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
return useMemo(() => {
|
||||
return (router.route === '/render' && origin === ORIGIN.CURRENT_PAGE) || origin === ORIGIN.RENDERER
|
||||
? baseUrls.renderer
|
||||
: baseUrls.editor
|
||||
}, [origin, baseUrls.renderer, baseUrls.editor, router.route])
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* Registers event listener for pointer movement and pointer release on the window object.
|
||||
*
|
||||
* @param onPointerMovement is triggered if the user moves the pointer over the window
|
||||
* @param onPointerRelease is triggered if the pointer is released (touch end or mouse up)
|
||||
*/
|
||||
export const useBindPointerMovementEventOnWindow = (
|
||||
onPointerMovement: (event: MouseEvent | TouchEvent) => void,
|
||||
onPointerRelease: () => void
|
||||
): void => {
|
||||
useEffect(() => {
|
||||
const pointerMovement = onPointerMovement
|
||||
const pointerRelease = onPointerRelease
|
||||
window.addEventListener('touchmove', pointerMovement)
|
||||
window.addEventListener('mousemove', pointerMovement)
|
||||
window.addEventListener('touchcancel', pointerRelease)
|
||||
window.addEventListener('touchend', pointerRelease)
|
||||
window.addEventListener('mouseup', pointerRelease)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('touchmove', pointerMovement)
|
||||
window.removeEventListener('mousemove', pointerMovement)
|
||||
window.removeEventListener('touchcancel', pointerRelease)
|
||||
window.removeEventListener('touchend', pointerRelease)
|
||||
window.removeEventListener('mouseup', pointerRelease)
|
||||
}
|
||||
}, [onPointerMovement, onPointerRelease])
|
||||
}
|
23
frontend/src/hooks/common/use-boolean-state.ts
Normal file
23
frontend/src/hooks/common/use-boolean-state.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
/**
|
||||
* Provides a boolean state and two functions that set the boolean to true or false.
|
||||
*
|
||||
* @param initialState The initial value of the state
|
||||
* @return An array containing the state, and two functions that set the state value to true or false.
|
||||
*/
|
||||
export const useBooleanState = (
|
||||
initialState: boolean | (() => boolean) = false
|
||||
): [state: boolean, setToTrue: () => void, setToFalse: () => void] => {
|
||||
const [state, setState] = useState(initialState)
|
||||
const setToFalse = useCallback(() => setState(false), [])
|
||||
const setToTrue = useCallback(() => setState(true), [])
|
||||
|
||||
return [state, setToTrue, setToFalse]
|
||||
}
|
21
frontend/src/hooks/common/use-dark-mode-state.ts
Normal file
21
frontend/src/hooks/common/use-dark-mode-state.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useApplicationState } from './use-application-state'
|
||||
import useMediaQuery from '@restart/hooks/useMediaQuery'
|
||||
import { DarkModePreference } from '../../redux/dark-mode/types'
|
||||
|
||||
/**
|
||||
* Uses the user settings and the browser preference to determine if dark mode should be used.
|
||||
*
|
||||
* @return The current state of the dark mode.
|
||||
*/
|
||||
export const useDarkModeState = (): boolean => {
|
||||
const preference = useApplicationState((state) => state.darkMode.darkModePreference)
|
||||
const isBrowserPreferringDark = useMediaQuery('(prefers-color-scheme: dark)')
|
||||
|
||||
return preference === DarkModePreference.DARK || (preference === DarkModePreference.AUTO && isBrowserPreferringDark)
|
||||
}
|
30
frontend/src/hooks/common/use-effect-with-catch.ts
Normal file
30
frontend/src/hooks/common/use-effect-with-catch.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { DependencyList, EffectCallback } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
/**
|
||||
* Executes a side effects but catches any thrown error.
|
||||
*
|
||||
* @param effect The side effect to execute
|
||||
* @param deps The dependencies of the effect
|
||||
* @return The produced error (if occurred)
|
||||
*/
|
||||
export const useEffectWithCatch = (effect: EffectCallback, deps: DependencyList = []): Error | undefined => {
|
||||
const [error, setError] = useState<Error | undefined>(undefined)
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
return effect()
|
||||
} catch (error) {
|
||||
setError(error as Error)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, deps)
|
||||
|
||||
return error
|
||||
}
|
16
frontend/src/hooks/common/use-note-markdown-content.ts
Normal file
16
frontend/src/hooks/common/use-note-markdown-content.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useApplicationState } from './use-application-state'
|
||||
|
||||
/**
|
||||
* Extracts the markdown content of the current note from the global application state.
|
||||
*
|
||||
* @return The markdown content of the note
|
||||
*/
|
||||
export const useNoteMarkdownContent = (): string => {
|
||||
return useApplicationState((state) => state.noteDetails.markdownContent.plain)
|
||||
}
|
22
frontend/src/hooks/common/use-note-title.ts
Normal file
22
frontend/src/hooks/common/use-note-title.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useApplicationState } from './use-application-state'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
/**
|
||||
* Retrieves the title of the note or a placeholder text, if no title is set.
|
||||
*
|
||||
* @return The title of the note
|
||||
*/
|
||||
export const useNoteTitle = (): string => {
|
||||
const { t } = useTranslation()
|
||||
const untitledNote = useMemo(() => t('editor.untitledNote'), [t])
|
||||
const noteTitle = useApplicationState((state) => state.noteDetails.title)
|
||||
|
||||
return useMemo(() => (noteTitle === '' ? untitledNote : noteTitle), [noteTitle, untitledNote])
|
||||
}
|
23
frontend/src/hooks/common/use-on-input-change.ts
Normal file
23
frontend/src/hooks/common/use-on-input-change.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import type { ChangeEvent } from 'react'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
/**
|
||||
* Takes an input change event and sends the event value to a state setter.
|
||||
*
|
||||
* @param setter The setter method for the state.
|
||||
* @return Hook that can be used as callback for onChange.
|
||||
*/
|
||||
export const useOnInputChange = (setter: (value: string) => void): ((event: ChangeEvent<HTMLInputElement>) => void) => {
|
||||
return useCallback(
|
||||
(event) => {
|
||||
setter(event.target.value)
|
||||
},
|
||||
[setter]
|
||||
)
|
||||
}
|
24
frontend/src/hooks/common/use-single-string-url-parameter.ts
Normal file
24
frontend/src/hooks/common/use-single-string-url-parameter.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
/**
|
||||
* Extracts the parameter from the router expected to be a single value.
|
||||
*
|
||||
* @param parameter The parameter to extract
|
||||
* @param fallback The fallback returned if there is no value.
|
||||
* @return A value extracted from the router.
|
||||
*/
|
||||
export const useSingleStringUrlParameter = <T>(parameter: string, fallback: T): string | T => {
|
||||
const router = useRouter()
|
||||
|
||||
return useMemo(() => {
|
||||
const value = router.query[parameter]
|
||||
return (typeof value === 'string' ? value : value?.[0]) ?? fallback
|
||||
}, [fallback, parameter, router.query])
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { useMemo } from 'react'
|
||||
import { useApplicationState } from './use-application-state'
|
||||
|
||||
/**
|
||||
* Returns the markdown content from the global application state trimmed to the maximal note length and without the frontmatter lines.
|
||||
*
|
||||
* @return The array of markdown content lines
|
||||
*/
|
||||
export const useTrimmedNoteMarkdownContentWithoutFrontmatter = (): string[] => {
|
||||
const maxLength = useApplicationState((state) => state.config.maxDocumentLength)
|
||||
const markdownContent = useApplicationState((state) => ({
|
||||
lines: state.noteDetails.markdownContent.lines,
|
||||
content: state.noteDetails.markdownContent.plain
|
||||
}))
|
||||
const lineOffset = useApplicationState((state) => state.noteDetails.frontmatterRendererInfo.lineOffset)
|
||||
|
||||
const trimmedLines = useMemo(() => {
|
||||
if (markdownContent.content.length > maxLength) {
|
||||
return markdownContent.content.slice(0, maxLength).split('\n')
|
||||
} else {
|
||||
return markdownContent.lines
|
||||
}
|
||||
}, [markdownContent, maxLength])
|
||||
|
||||
return useMemo(() => {
|
||||
return trimmedLines.slice(lineOffset)
|
||||
}, [lineOffset, trimmedLines])
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue