diff --git a/frontend/cypress/e2e/intro.spec.ts b/frontend/cypress/e2e/intro.spec.ts
index 2e3ac7e52..c63905845 100644
--- a/frontend/cypress/e2e/intro.spec.ts
+++ b/frontend/cypress/e2e/intro.spec.ts
@@ -1,5 +1,5 @@
/*
- * 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
*/
@@ -36,14 +36,4 @@ describe('Intro page', () => {
cy.getByCypressId('sign-in-button').should('exist')
})
})
-
- describe('version dialog', () => {
- it('can be opened and closed', () => {
- cy.getByCypressId('version-modal').should('not.exist')
- cy.getByCypressId('show-version-modal').click()
- cy.getByCypressId('version-modal').should('be.visible')
- cy.getByCypressId('version-modal').find('.modal-header .btn-close').click()
- cy.getByCypressId('version-modal').should('not.exist')
- })
- })
})
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index 22ccb8d19..e758e986d 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -147,11 +147,7 @@
},
"footer": {
"releases": "Releases",
- "poweredBy": "Powered by <0>0>",
- "imprint": "Imprint",
- "followUs": "Follow us on <0>0>, <1>1>, <2>2>, <3>3>, and <4>4>.",
- "privacy": "Privacy",
- "termsOfUse": "Terms of Use"
+ "poweredBy": "Powered by <0>0>"
},
"versionInfo": {
"issueTracker": "Found a bug? Fill an issue!",
@@ -485,11 +481,36 @@
}
},
"appbar": {
+ "editor": {
+ "readOnly": "read-only"
+ },
"help": {
"help": {
"header": "Help",
"shortcuts": "Shortcuts",
"cheatsheet": "Cheatsheet"
+ },
+ "instance": {
+ "header": "About this instance",
+ "versionInfo": "Running version"
+ },
+ "legal": {
+ "header": "Legal",
+ "privacy": "Privacy Policy",
+ "termsOfUse": "Terms of use",
+ "imprint": "Imprint"
+ },
+ "project": {
+ "header": "Project",
+ "github": "Project on GitHub",
+ "reportIssue": "Report an issue",
+ "helpTranslating": "Help us translating"
+ },
+ "social": {
+ "header": "Social",
+ "discourse": "Join the community",
+ "matrix": "Chat with us on Matrix",
+ "mastodon": "Follow us on Mastodon"
}
}
},
@@ -642,7 +663,6 @@
}
},
"cheatsheet": {
- "button": "Open Cheatsheet",
"search": "Search for Cheatsheets",
"modal": {
"popup": "Open in new tab",
diff --git a/frontend/src/components/common/custom-branding/__snapshots__/custom-branding.spec.tsx.snap b/frontend/src/components/common/custom-branding/__snapshots__/custom-branding.spec.tsx.snap
index 3fd60b783..aba5f84f6 100644
--- a/frontend/src/components/common/custom-branding/__snapshots__/custom-branding.spec.tsx.snap
+++ b/frontend/src/components/common/custom-branding/__snapshots__/custom-branding.spec.tsx.snap
@@ -35,7 +35,7 @@ exports[`custom branding with inline=false will prefer the logo over the text 1`
exports[`custom branding with inline=true shows an image if branding logo is defined 1`] = `
@@ -44,7 +44,7 @@ exports[`custom branding with inline=true shows an image if branding logo is def
exports[`custom branding with inline=true shows an text if branding text is defined 1`] = `
mockedBranding
@@ -55,7 +55,7 @@ exports[`custom branding with inline=true will prefer the logo over the text 1`]
diff --git a/frontend/src/components/editor-page/app-bar/branding-separator-dash.tsx b/frontend/src/components/common/custom-branding/branding-separator-dash.tsx
similarity index 81%
rename from frontend/src/components/editor-page/app-bar/branding-separator-dash.tsx
rename to frontend/src/components/common/custom-branding/branding-separator-dash.tsx
index 83855ced4..2327b55cd 100644
--- a/frontend/src/components/editor-page/app-bar/branding-separator-dash.tsx
+++ b/frontend/src/components/common/custom-branding/branding-separator-dash.tsx
@@ -3,7 +3,7 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { useBrandingDetails } from '../../common/custom-branding/use-branding-details'
+import { useBrandingDetails } from './use-branding-details'
import React from 'react'
/**
diff --git a/frontend/src/components/common/custom-branding/branding.module.scss b/frontend/src/components/common/custom-branding/branding.module.scss
index f4823f262..c3702dc12 100644
--- a/frontend/src/components/common/custom-branding/branding.module.scss
+++ b/frontend/src/components/common/custom-branding/branding.module.scss
@@ -1,4 +1,4 @@
-/*
+/*!
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
@@ -8,6 +8,11 @@
height: 50px;
}
-.inline-size {
- height: 30px;
+.inline-logo {
+ height: 32px;
+}
+
+.inline-text {
+ font-size: 18px;
+ line-height: 1.0;
}
diff --git a/frontend/src/components/common/custom-branding/custom-branding.tsx b/frontend/src/components/common/custom-branding/custom-branding.tsx
index d2e6fe5e9..e0f79dd44 100644
--- a/frontend/src/components/common/custom-branding/custom-branding.tsx
+++ b/frontend/src/components/common/custom-branding/custom-branding.tsx
@@ -3,9 +3,10 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import { concatCssClasses } from '../../../utils/concat-css-classes'
import styles from './branding.module.scss'
import { useBrandingDetails } from './use-branding-details'
-import React from 'react'
+import React, { useMemo } from 'react'
export interface BrandingProps {
inline?: boolean
@@ -16,12 +17,19 @@ export interface BrandingProps {
* This branding can either be a text, a logo or both (in that case the text is used as the title and alt of the image).
*
* @param inline If the logo should be using the inline-size or the regular-size css class.
- * @param delimiter If the delimiter between the HedgeDoc logo and the branding should be shown.
*/
export const CustomBranding: React.FC = ({ inline = false }) => {
const branding = useBrandingDetails()
- const className = inline ? styles['inline-size'] : styles['regular-size']
+ const className = useMemo(
+ () =>
+ concatCssClasses({
+ [styles['regular-size']]: !inline,
+ [styles['inline-logo']]: inline && branding && !!branding.logo,
+ [styles['inline-text']]: inline && branding && !branding.logo
+ }),
+ [inline, branding]
+ )
if (!branding) {
return null
diff --git a/frontend/src/components/editor-page/app-bar/app-bar.tsx b/frontend/src/components/editor-page/app-bar/app-bar.tsx
deleted file mode 100644
index 491943c61..000000000
--- a/frontend/src/components/editor-page/app-bar/app-bar.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 { useOutlineButtonVariant } from '../../../hooks/dark-mode/use-outline-button-variant'
-import { CheatsheetButton } from '../../cheatsheet/cheatsheet-button'
-import { NewNoteButton } from '../../common/new-note-button/new-note-button'
-import { ShowIf } from '../../common/show-if/show-if'
-import { SettingsButton } from '../../global-dialogs/settings-dialog/settings-button'
-import { SignInButton } from '../../landing-layout/navigation/sign-in-button'
-import { UserDropdown } from '../../landing-layout/navigation/user-dropdown'
-import { HelpButton } from './help-button/help-button'
-import { NavbarBranding } from './navbar-branding'
-import { ReadOnlyModeButton } from './read-only-mode-button'
-import { SlideModeButton } from './slide-mode-button'
-import { NoteType } from '@hedgedoc/commons'
-import React from 'react'
-import { Nav, Navbar } from 'react-bootstrap'
-
-export enum AppBarMode {
- BASIC,
- EDITOR
-}
-
-export interface AppBarProps {
- mode: AppBarMode
-}
-
-/**
- * Renders the app bar.
- *
- * @param mode Which mode the app bar should be rendered in. This mainly adds / removes buttons for the editor.
- */
-export const AppBar: React.FC = ({ mode }) => {
- const userExists = useApplicationState((state) => !!state.user)
- const noteFrontmatter = useApplicationState((state) => state.noteDetails.frontmatter)
- const buttonVariant = useOutlineButtonVariant()
-
- return (
-
-
-
-
- )
-}
diff --git a/frontend/src/components/editor-page/app-bar/help-button/help-button.tsx b/frontend/src/components/editor-page/app-bar/help-button/help-button.tsx
deleted file mode 100644
index 2c00ee0ee..000000000
--- a/frontend/src/components/editor-page/app-bar/help-button/help-button.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import { useBooleanState } from '../../../../hooks/common/use-boolean-state'
-import { useTranslatedText } from '../../../../hooks/common/use-translated-text'
-import { useOutlineButtonVariant } from '../../../../hooks/dark-mode/use-outline-button-variant'
-import { cypressId } from '../../../../utils/cypress-attribute'
-import { IconButton } from '../../../common/icon-button/icon-button'
-import { ShortcutsModal } from '../../../global-dialogs/shortcuts-modal/shortcuts-modal'
-import React, { Fragment } from 'react'
-import { QuestionCircle as IconQuestionCircle } from 'react-bootstrap-icons'
-import { Trans } from 'react-i18next'
-
-/**
- * Renders the button to open the shortcuts modal.
- */
-export const HelpButton: React.FC = () => {
- const [modalVisibility, showModal, closeModal] = useBooleanState()
- const buttonVariant = useOutlineButtonVariant()
- const buttonTitle = useTranslatedText('editor.documentBar.help')
-
- return (
-
-
-
-
-
-
- )
-}
diff --git a/frontend/src/components/editor-page/app-bar/navbar-branding.tsx b/frontend/src/components/editor-page/app-bar/navbar-branding.tsx
deleted file mode 100644
index f518455c8..000000000
--- a/frontend/src/components/editor-page/app-bar/navbar-branding.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import { useDarkModeState } from '../../../hooks/dark-mode/use-dark-mode-state'
-import { CustomBranding } from '../../common/custom-branding/custom-branding'
-import { HedgeDocLogoHorizontalGrey } from '../../common/hedge-doc-logo/hedge-doc-logo-horizontal-grey'
-import { LogoSize } from '../../common/hedge-doc-logo/logo-size'
-import { BrandingSeparatorDash } from './branding-separator-dash'
-import Link from 'next/link'
-import React from 'react'
-import { Navbar } from 'react-bootstrap'
-
-/**
- * Renders the branding for the {@link AppBar}
- */
-export const NavbarBranding: React.FC = () => {
- const darkModeActivated = useDarkModeState()
-
- return (
-
-
-
-
-
-
-
- )
-}
diff --git a/frontend/src/components/editor-page/app-bar/read-only-mode-button.tsx b/frontend/src/components/editor-page/app-bar/read-only-mode-button.tsx
deleted file mode 100644
index 5ba8509ed..000000000
--- a/frontend/src/components/editor-page/app-bar/read-only-mode-button.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import { useApplicationState } from '../../../hooks/common/use-application-state'
-import { useTranslatedText } from '../../../hooks/common/use-translated-text'
-import { useOutlineButtonVariant } from '../../../hooks/dark-mode/use-outline-button-variant'
-import { UiIcon } from '../../common/icons/ui-icon'
-import Link from 'next/link'
-import React from 'react'
-import { Button } from 'react-bootstrap'
-import { FileEarmarkTextFill as IconFileEarmarkTextFill } from 'react-bootstrap-icons'
-
-/**
- * Button that links to the read-only version of a note.
- */
-export const ReadOnlyModeButton: React.FC = () => {
- const noteIdentifier = useApplicationState((state) => state.noteDetails.primaryAddress)
- const buttonVariant = useOutlineButtonVariant()
- const buttonTitle = useTranslatedText('editor.documentBar.readOnlyMode')
-
- return (
-
-
-
- )
-}
diff --git a/frontend/src/components/editor-page/app-bar/slide-mode-button.tsx b/frontend/src/components/editor-page/app-bar/slide-mode-button.tsx
deleted file mode 100644
index 2c31173e8..000000000
--- a/frontend/src/components/editor-page/app-bar/slide-mode-button.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import { useApplicationState } from '../../../hooks/common/use-application-state'
-import { useTranslatedText } from '../../../hooks/common/use-translated-text'
-import { useOutlineButtonVariant } from '../../../hooks/dark-mode/use-outline-button-variant'
-import { UiIcon } from '../../common/icons/ui-icon'
-import Link from 'next/link'
-import React from 'react'
-import { Button } from 'react-bootstrap'
-import { Tv as IconTv } from 'react-bootstrap-icons'
-
-/**
- * Button that links to the slide-show presentation of the current note.
- */
-export const SlideModeButton: React.FC = () => {
- const noteIdentifier = useApplicationState((state) => state.noteDetails.primaryAddress)
- const buttonVariant = useOutlineButtonVariant()
- const buttonTitle = useTranslatedText('editor.documentBar.slideMode')
-
- return (
-
-
-
- )
-}
diff --git a/frontend/src/components/editor-page/editor-page-content.tsx b/frontend/src/components/editor-page/editor-page-content.tsx
index 30eff1c2d..3803a775a 100644
--- a/frontend/src/components/editor-page/editor-page-content.tsx
+++ b/frontend/src/components/editor-page/editor-page-content.tsx
@@ -6,9 +6,9 @@
import { useApplyDarkModeStyle } from '../../hooks/dark-mode/use-apply-dark-mode-style'
import { useSaveDarkModePreferenceToLocalStorage } from '../../hooks/dark-mode/use-save-dark-mode-preference-to-local-storage'
import { MotdModal } from '../global-dialogs/motd-modal/motd-modal'
+import { EditorAppBar } from '../layout/app-bar/editor-app-bar'
import { CommunicatorImageLightbox } from '../markdown-renderer/extensions/image/communicator-image-lightbox'
import { ExtensionEventEmitterProvider } from '../markdown-renderer/hooks/use-extension-event-emitter'
-import { AppBar, AppBarMode } from './app-bar/app-bar'
import { ChangeEditorContentContextProvider } from './change-content-context/codemirror-reference-context'
import { EditorPane } from './editor-pane/editor-pane'
import { useComponentsFromAppExtensions } from './editor-pane/hooks/use-components-from-app-extensions'
@@ -16,7 +16,6 @@ import { HeadMetaProperties } from './head-meta-properties/head-meta-properties'
import { useScrollState } from './hooks/use-scroll-state'
import { useSetScrollSource } from './hooks/use-set-scroll-source'
import { useUpdateLocalHistoryEntry } from './hooks/use-update-local-history-entry'
-import { RealtimeConnectionAlert } from './realtime-connection-alert/realtime-connection-alert'
import { RendererPane } from './renderer-pane/renderer-pane'
import { Sidebar } from './sidebar/sidebar'
import { Splitter } from './splitter/splitter'
@@ -77,8 +76,7 @@ export const EditorPageContent: React.FC = () => {
-
-
+
realtime.connecting
@@ -11,5 +11,3 @@ exports[`realtime connection alert will show if not synced 1`] = `
`;
-
-exports[`realtime connection alert won't show if synced 1`] = ``;
diff --git a/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.spec.tsx b/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.spec.tsx
index fee16a247..af6d85dba 100644
--- a/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.spec.tsx
+++ b/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.spec.tsx
@@ -3,26 +3,14 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import * as UseApplicationStateModule from '../../../hooks/common/use-application-state'
import { mockI18n } from '../../../test-utils/mock-i18n'
import { RealtimeConnectionAlert } from './realtime-connection-alert'
import { render } from '@testing-library/react'
-jest.mock('../../../hooks/common/use-application-state')
-
describe('realtime connection alert', () => {
beforeAll(mockI18n)
- it("won't show if synced", () => {
- jest.spyOn(UseApplicationStateModule, 'useApplicationState').mockImplementation(() => true)
-
- const view = render()
- expect(view.container).toMatchSnapshot()
- })
-
- it('will show if not synced', () => {
- jest.spyOn(UseApplicationStateModule, 'useApplicationState').mockImplementation(() => false)
-
+ it('will render correctly', () => {
const view = render()
expect(view.container).toMatchSnapshot()
})
diff --git a/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.tsx b/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.tsx
index bf1525f36..45a81dcd5 100644
--- a/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.tsx
+++ b/frontend/src/components/editor-page/realtime-connection-alert/realtime-connection-alert.tsx
@@ -1,11 +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
*/
-import { useApplicationState } from '../../../hooks/common/use-application-state'
import { UiIcon } from '../../common/icons/ui-icon'
-import React, { Fragment } from 'react'
+import React from 'react'
import { Alert } from 'react-bootstrap'
import { ArrowRepeat as IconArrowRepeat } from 'react-bootstrap-icons'
import { Trans, useTranslation } from 'react-i18next'
@@ -14,15 +13,10 @@ import { Trans, useTranslation } from 'react-i18next'
* Modal with a spinner that is only shown while reconnecting to the realtime backend
*/
export const RealtimeConnectionAlert: React.FC = () => {
- const isSynced = useApplicationState((state) => state.realtimeStatus.isSynced)
useTranslation()
- if (isSynced) {
- return
- }
-
return (
-
+
diff --git a/frontend/src/components/landing-layout/footer/footer.tsx b/frontend/src/components/landing-layout/footer/footer.tsx
deleted file mode 100644
index 193d23c20..000000000
--- a/frontend/src/components/landing-layout/footer/footer.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import { PoweredByLinks } from './powered-by-links'
-import { SocialLink } from './social-links'
-import React from 'react'
-
-/**
- * Renders the footer.
- */
-export const Footer: React.FC = () => {
- return (
-
- )
-}
diff --git a/frontend/src/components/landing-layout/footer/powered-by-links.tsx b/frontend/src/components/landing-layout/footer/powered-by-links.tsx
deleted file mode 100644
index 8fd436884..000000000
--- a/frontend/src/components/landing-layout/footer/powered-by-links.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
- *
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-import links from '../../../links.json'
-import { useFrontendConfig } from '../../common/frontend-config-context/use-frontend-config'
-import { ExternalLink } from '../../common/links/external-link'
-import { TranslatedExternalLink } from '../../common/links/translated-external-link'
-import { TranslatedInternalLink } from '../../common/links/translated-internal-link'
-import { VersionInfoLink } from './version-info/version-info-link'
-import React, { Fragment, useMemo } from 'react'
-import { Trans, useTranslation } from 'react-i18next'
-
-/**
- * Renders a powered-by link.
- */
-export const PoweredByLinks: React.FC = () => {
- useTranslation()
-
- const rawSpecialUrls = useFrontendConfig().specialUrls
-
- const specialUrls = useMemo(
- () => Object.entries(rawSpecialUrls).map(([i18nkey, url]) => [i18nkey, String(url)]),
- [rawSpecialUrls]
- )
-
- return (
-