From 9e9108ec9a57d71cb6543503a51fd65cabc4c434 Mon Sep 17 00:00:00 2001 From: Erik Michelson Date: Mon, 12 Oct 2020 21:58:00 +0200 Subject: [PATCH] Add read-only view (/s/note) (#563) * Update Link classes to allow tooltips/titles * Added read-only-view, Move note title extraction into separate file (cherry picked from commit be23083ca3966f26b1b841d5cf4f21e299c8a55a) (cherry picked from commit cbc595d3fc336b0a649c396dfae30fa08082384c) * Optimized look of document-infobar (cherry picked from commit 0176668b156da3fd7c534161a839ca0e3495119c) # Conflicts: # src/components/editor/document-bar/document-info/document-info-time-line.tsx * Show help-button only in Editor-variant of AppBar (cherry picked from commit 3c26e1619c774fe162cb3d8fae9e79ced92c9c3e) * Update CHANGELOG (cherry picked from commit d0d29e7d408515cc8f86df45d13fff60d741873e) * Move motd-banner to top of page (cherry picked from commit 43a9a274bf5da3fdf640ec905ab38153c81b014b) * Refactor isInline to size property (cherry picked from commit cb4ee74b7c97ec9711946f28924e9c890b752ea3) # Conflicts: # src/components/editor/document-bar/document-info/document-info-time-line.tsx * Add size attribute to user-avatar (cherry picked from commit 9629b58911b9d4f3aed81ef8c271fbc8e5a15aa4) * Add mode-enum to app-bar (cherry picked from commit 08f95be58974468c1e2897b475e5e3235b79c230) * Split DocumentRenderPane into scrollable- and non-scrollable variant (cherry picked from commit 44dd27edfd967745c548f7ae1fd2047e812cdc22) * Removed unnecessary className --- CHANGELOG.md | 9 +- public/api/v2/notes/banner | 7 +- public/api/v2/notes/old | 7 +- public/locales/en.json | 12 ++ src/api/notes/index.ts | 7 +- .../document-title/note-title-extractor.ts | 11 ++ src/components/common/links/external-link.tsx | 3 +- src/components/common/links/internal-link.tsx | 3 +- src/components/common/links/types.d.ts | 1 + .../common/user-avatar/user-avatar.scss | 13 ++- .../common/user-avatar/user-avatar.tsx | 15 +-- src/components/editor/app-bar/app-bar.tsx | 21 +++- .../document-info/document-info-button.tsx | 6 +- .../document-info/document-info-line.tsx | 5 +- .../document-info-time-line.scss | 4 - .../document-info/document-info-time-line.tsx | 8 +- .../document-render-pane.tsx | 105 +++-------------- .../scrolling-document-render-pane.tsx | 107 ++++++++++++++++++ src/components/editor/editor.tsx | 20 ++-- .../pad-view-only/document-infobar.scss | 4 + .../pad-view-only/document-infobar.tsx | 60 ++++++++++ .../pad-view-only/pad-view-only.tsx | 90 +++++++++++++++ src/index.tsx | 4 + 23 files changed, 379 insertions(+), 143 deletions(-) create mode 100644 src/components/common/document-title/note-title-extractor.ts delete mode 100644 src/components/editor/document-bar/document-info/document-info-time-line.scss create mode 100644 src/components/editor/document-renderer-pane/scrolling-document-render-pane.tsx create mode 100644 src/components/pad-view-only/document-infobar.scss create mode 100644 src/components/pad-view-only/document-infobar.tsx create mode 100644 src/components/pad-view-only/pad-view-only.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index d024be730..195ac77c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,9 +32,9 @@ - Highlighted code blocks can now use line wrapping and line numbers at once - Images, videos, and other non-text content is now wider in View Mode - Notes may now be deleted directly from the history page -- HedgeDoc instances can now be branded either with a '@ ' or '@ ' after the HedgeDoc logo and text +- HedgeDoc instances can be branded either with a '@ \' or '@ \' after the HedgeDoc logo and text - Images will be loaded via proxy if an image proxy is configured in the backend -- Asciinema videos may now be embedded by pasting the URL of one video into a single line +- Asciinema videos may be embedded by pasting the URL of one video into a single line - The toolbar includes an emoji and fork-awesome icon picker. - Collapsable blocks can be added via a toolbar button or via autocompletion of " (add image) and (add link) toolbar buttons, put selected links directly in the `()` instead of the `[]` part of the generated markdown +- The (add image) and (add link) toolbar buttons put selected links directly in the `()` instead of the `[]` part of the generated markdown. - The help dialog has multiple tabs, and is a bit more organized. - Use KaTeX instead of MathJax. ([Why?](https://community.codimd.org/t/frequently-asked-questions/190)) -- The access tokens for the CLI and 3rd-party-clients can be managed in the user profile. +- The dark-mode is also applied to the read-only-view and can be toggled from there. +- Access tokens for the CLI and 3rd-party-clients can be managed in the user profile. --- diff --git a/public/api/v2/notes/banner b/public/api/v2/notes/banner index 9ec51b790..3642978c1 100644 --- a/public/api/v2/notes/banner +++ b/public/api/v2/notes/banner @@ -2,12 +2,11 @@ "id": "ABC123", "alias": "banner", "lastChange": { - "userId": "snskxnksnxksnxksnx", - "username": "testy", - "timestamp": 123456789 + "userId": "test", + "timestamp": 1600033920 }, "viewcount": 0, - "createtime": "2020-05-22T20:46:08.962Z", + "createtime": 1600033920, "content": "This is the test banner text", "authorship": [], "preVersionTwoNote": true diff --git a/public/api/v2/notes/old b/public/api/v2/notes/old index 07e07dc88..c4b194892 100644 --- a/public/api/v2/notes/old +++ b/public/api/v2/notes/old @@ -2,12 +2,11 @@ "id": "ABC123", "alias": "old", "lastChange": { - "userId": "snskxnksnxksnxksnx", - "username": "testy", - "timestamp": 123456789 + "userId": "test", + "timestamp": 1600033920 }, "viewcount": 0, - "createtime": "2020-05-22T20:46:08.962Z", + "createtime": 1600033920, "content": "test123", "authorship": [], "preVersionTwoNote": false diff --git a/public/locales/en.json b/public/locales/en.json index 3dac48fda..9c9fa1170 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -393,6 +393,18 @@ "clickToLoad": "Click to load" } }, + "views": { + "presentation": {}, + "readOnly": { + "viewCount": "views", + "editNote": "Edit this note", + "loading": "Loading note contents ...", + "error": { + "title": "Error while loading note", + "description": "Probably the requested note does not exist or was deleted." + } + } + }, "common": { "import": "Import", "export": "Export", diff --git a/src/api/notes/index.ts b/src/api/notes/index.ts index d96e1f8e8..adeb77634 100644 --- a/src/api/notes/index.ts +++ b/src/api/notes/index.ts @@ -2,7 +2,6 @@ import { defaultFetchConfig, expectResponseCode, getApiUrl } from '../utils' interface LastChange { userId: string - username: string timestamp: number } @@ -11,14 +10,16 @@ export interface Note { alias: string lastChange: LastChange viewcount: number - createtime: string + createtime: number content: string authorship: number[] preVersionTwoNote: boolean } export const getNote = async (noteId: string): Promise => { - const response = await fetch(getApiUrl() + `/notes/${noteId}`) + const response = await fetch(getApiUrl() + `/notes/${noteId}`, { + ...defaultFetchConfig + }) expectResponseCode(response) return await response.json() as Promise } diff --git a/src/components/common/document-title/note-title-extractor.ts b/src/components/common/document-title/note-title-extractor.ts new file mode 100644 index 000000000..ca1346b36 --- /dev/null +++ b/src/components/common/document-title/note-title-extractor.ts @@ -0,0 +1,11 @@ +import { YAMLMetaData } from '../../editor/yaml-metadata/yaml-metadata' + +export const extractNoteTitle = (defaultTitle: string, noteMetadata?: YAMLMetaData, firstHeading?: string): string => { + if (noteMetadata?.title && noteMetadata?.title !== '') { + return noteMetadata.title + } else if (noteMetadata?.opengraph && noteMetadata?.opengraph.get('title') && noteMetadata?.opengraph.get('title') !== '') { + return (noteMetadata?.opengraph.get('title') ?? defaultTitle) + } else { + return (firstHeading ?? defaultTitle).trim() + } +} diff --git a/src/components/common/links/external-link.tsx b/src/components/common/links/external-link.tsx index 8736a790c..6c1021e53 100644 --- a/src/components/common/links/external-link.tsx +++ b/src/components/common/links/external-link.tsx @@ -4,13 +4,14 @@ import { IconName } from '../fork-awesome/types' import { ShowIf } from '../show-if/show-if' import { LinkWithTextProps } from './types' -export const ExternalLink: React.FC = ({ href, text, icon, id, className = 'text-light' }) => { +export const ExternalLink: React.FC = ({ href, text, icon, id, className = 'text-light', title }) => { return ( diff --git a/src/components/common/links/internal-link.tsx b/src/components/common/links/internal-link.tsx index 7fc1a4f95..34def4159 100644 --- a/src/components/common/links/internal-link.tsx +++ b/src/components/common/links/internal-link.tsx @@ -5,11 +5,12 @@ import { IconName } from '../fork-awesome/types' import { ShowIf } from '../show-if/show-if' import { LinkWithTextProps } from './types' -export const InternalLink: React.FC = ({ href, text, icon, id, className = 'text-light' }) => { +export const InternalLink: React.FC = ({ href, text, icon, id, className = 'text-light', title }) => { return (   diff --git a/src/components/common/links/types.d.ts b/src/components/common/links/types.d.ts index f6298252d..b9d6ad168 100644 --- a/src/components/common/links/types.d.ts +++ b/src/components/common/links/types.d.ts @@ -6,6 +6,7 @@ interface GeneralLinkProp { icon?: IconName id?: string className?: string + title?: string } export interface LinkWithTextProps extends GeneralLinkProp { diff --git a/src/components/common/user-avatar/user-avatar.scss b/src/components/common/user-avatar/user-avatar.scss index 8f15e9959..a1c9dd4f0 100644 --- a/src/components/common/user-avatar/user-avatar.scss +++ b/src/components/common/user-avatar/user-avatar.scss @@ -1,8 +1,15 @@ .user-avatar { width: 20px; height: 20px; -} -.user-name { - font-size: 1rem; + &.lg { + width: 30px; + height: 30px; + } + + &.sm { + width: 16px; + height: 16px; + } + } diff --git a/src/components/common/user-avatar/user-avatar.tsx b/src/components/common/user-avatar/user-avatar.tsx index 64b4f73ce..e5e808972 100644 --- a/src/components/common/user-avatar/user-avatar.tsx +++ b/src/components/common/user-avatar/user-avatar.tsx @@ -4,25 +4,26 @@ import { ShowIf } from '../show-if/show-if' import './user-avatar.scss' export interface UserAvatarProps { - name: string; - photo: string; - additionalClasses?: string; - showName?: boolean + size?: 'sm' | 'lg' + name: string; + photo: string; + additionalClasses?: string; + showName?: boolean } -const UserAvatar: React.FC = ({ name, photo, additionalClasses = '', showName = true }) => { +const UserAvatar: React.FC = ({ name, photo, size, additionalClasses = '', showName = true }) => { const { t } = useTranslation() return ( {t('common.avatarOf', - {name} + {name} ) diff --git a/src/components/editor/app-bar/app-bar.tsx b/src/components/editor/app-bar/app-bar.tsx index 3c380ded9..90781e149 100644 --- a/src/components/editor/app-bar/app-bar.tsx +++ b/src/components/editor/app-bar/app-bar.tsx @@ -16,7 +16,16 @@ import { HelpButton } from './help-button/help-button' import { NavbarBranding } from './navbar-branding' import { SyncScrollButtons } from './sync-scroll-buttons/sync-scroll-buttons' -export const AppBar: React.FC = () => { +export enum AppBarMode { + BASIC, + EDITOR +} + +export interface AppBarProps { + mode: AppBarMode +} + +export const AppBar: React.FC = ({ mode }) => { const { t } = useTranslation() const { id } = useParams() const userExists = useSelector((state: ApplicationState) => !!state.user) @@ -25,15 +34,19 @@ export const AppBar: React.FC = () => {