diff --git a/app/assets/javascripts/components/NotesOptions.tsx b/app/assets/javascripts/components/NotesOptions.tsx index 3346ff1e4..d95548af5 100644 --- a/app/assets/javascripts/components/NotesOptions.tsx +++ b/app/assets/javascripts/components/NotesOptions.tsx @@ -2,7 +2,7 @@ import { AppState } from '@/ui_models/app_state'; import { Icon } from './Icon'; import { Switch } from './Switch'; import { observer } from 'mobx-react-lite'; -import { useRef, useState, useEffect } from 'preact/hooks'; +import { useRef, useState, useEffect, useMemo } from 'preact/hooks'; import { Disclosure, DisclosureButton, @@ -11,6 +11,7 @@ import { import { SNNote } from '@standardnotes/snjs/dist/@types'; import { WebApplication } from '@/ui_models/application'; import { KeyboardModifier } from '@/services/ioService'; +import { FunctionComponent } from 'preact'; type Props = { application: WebApplication; @@ -20,9 +21,9 @@ type Props = { }; type DeletePermanentlyButtonProps = { - closeOnBlur: Props["closeOnBlur"]; + closeOnBlur: Props['closeOnBlur']; onClick: () => void; -} +}; const DeletePermanentlyButton = ({ closeOnBlur, @@ -34,6 +35,87 @@ const DeletePermanentlyButton = ({ ); +const countNoteAttributes = (text: string) => { + try { + JSON.parse(text); + return { + characters: 'N/A', + words: 'N/A', + paragraphs: 'N/A', + }; + } catch { + const characters = text.length; + const words = text.match(/[\w’'-]+\b/g)?.length; + const paragraphs = text.replace(/\n$/gm, '').split(/\n/).length; + + return { + characters, + words, + paragraphs, + }; + } +}; + +const calculateReadTime = (words: number) => { + const timeToRead = Math.round(words / 200); + if (timeToRead === 0) { + return '< 1 minute'; + } else { + return `${timeToRead} ${timeToRead > 1 ? 'minutes' : 'minute'}`; + } +}; + +const formatDate = (date: Date | undefined) => { + if (!date) return; + return `${date.toDateString()} ${date.toLocaleTimeString()}`; +}; + +const NoteAttributes: FunctionComponent<{ note: SNNote }> = ({ note }) => { + const { words, characters, paragraphs } = useMemo( + () => countNoteAttributes(note.text), + [note.text] + ); + + const readTime = useMemo( + () => (typeof words === 'number' ? calculateReadTime(words) : 'N/A'), + [words] + ); + + const dateLastModified = useMemo( + () => formatDate(note.serverUpdatedAt), + [note.serverUpdatedAt] + ); + + const dateCreated = useMemo( + () => formatDate(note.created_at), + [note.created_at] + ); + + return ( +