|
- import * as React from 'react'
- import Head from 'next/head'
- import styled from 'styled-components'
- import { useRouter } from 'next/router'
- import Editor from '../components/Editor/Editor'
- import Navbar from '../components/Navbar/Navbar'
- import generateId from '../utilities/Id'
- import { formatDate } from '../utilities/Date'
- import * as Note from '../controllers/Note'
- import * as Folder from '../controllers/Folder'
-
- const Main = styled('main')({
- margin: '2rem 0',
- '@media (min-width: 1080px)': {
- paddingLeft: `${100 / 3}%`,
- boxSizing: 'border-box',
- },
- })
-
- const Container = styled('div')({
- width: '100%',
- margin: '0 auto',
- padding: '0 1rem',
- boxSizing: 'border-box',
- '@media (min-width: 720px)': {
- maxWidth: 720,
- },
- })
-
- const TitleInput = styled('input')({
- border: 0,
- background: 'transparent',
- padding: 0,
- display: 'block',
- width: '100%',
- font: 'inherit',
- fontSize: '3rem',
- fontWeight: 'bold',
- color: 'inherit',
- outline: 0,
- })
-
- const PostMeta = styled('small')({
- opacity: 0.5,
- height: '1.25rem',
- display: 'block',
- lineHeight: 1.25,
- })
-
- const PostPrimary = styled('div')({
- marginBottom: '2rem',
- })
-
- type NoteInstance = { id: string, title: string, content?: object, updatedAt: string, }
-
- const Notes = ({ id: idProp }) => {
- // TODO remove extra state for ID
- const [id, setId, ] = React.useState(idProp)
- const [title, setTitle, ] = React.useState('')
- const [notes, setNotes, ] = React.useState(null)
- const [folders, setFolders, ] = React.useState(null)
- const stateRef = React.useRef<NoteInstance>({ id, title: '', updatedAt: new Date().toISOString(), })
- const timeoutRef = React.useRef<number>(null)
- const router = useRouter()
-
- React.useEffect(() => {
- Note.load({ setNotes })
- }, [])
-
- React.useEffect(() => {
- Folder.load({ setFolders })
- }, [])
-
- React.useEffect(() => {
- if (!Array.isArray(notes!)) {
- return
- }
- const theNote = notes.find(n => n.id === id)
- stateRef.current = theNote ? theNote : { id, title: '', updatedAt: new Date().toISOString(), }
- setTitle(stateRef.current.title)
- }, [id, notes])
-
- React.useEffect(() => {
- setId(idProp || generateId())
- }, [idProp])
-
- return (
- <React.Fragment>
- <Head>
- <title>{ idProp === undefined ? 'Notes | New Note' : `Notes | Edit Note - ${title.length > 0 ? title : '(untitled)'}`}</title>
- <link rel="icon" href="/favicon.ico" />
- </Head>
- <Navbar
- closeHref={{
- pathname: router.pathname,
- query: Object
- .entries(router.query)
- .filter(([key]) => key !== 'navbar')
- .reduce(
- (theQuery, [key, value]) => ({
- ...theQuery,
- [key]: value,
- }),
- {}
- ),
- }}
- secondaryVisible={Boolean(router.query.navbar)}
- primaryItemsStart={[
- {
- id: 'sidebar',
- mobileOnly: true,
- active: Boolean(router.query.navbar),
- href: {
- pathname: router.pathname,
- query: {
- ...router.query,
- navbar: 'true',
- },
- },
- iconName: 'menu',
- title: 'Menu',
- },
- {
- id: 'folders',
- active: router.pathname.startsWith('/notes') && !Boolean(router.query.navbar),
- href: {
- pathname: '/notes',
- },
- iconName: 'note',
- title: 'Notes',
- },
- {
- id: 'search',
- href: {
- pathname: '/notes',
- query: {
- action: 'search',
- },
- },
- iconName: 'search',
- title: 'Search',
- },
- {
- id: 'binned',
- href: {
- pathname: '/notes',
- query: {
- status: 'binned',
- },
- },
- iconName: 'bin',
- title: 'Bin',
- },
- ]}
- primaryItemsEnd={[
- {
- id: 'user',
- href: {
- pathname: '/me',
- },
- iconName: 'user',
- title: 'User',
- },
- ]}
- secondaryItemsHeader={[
- {
- id: 'parent',
- href: {
- pathname: '/notes',
- query: {
- folder: '00000000-0000-0000-000000000000',
- navbar: router.query.navbar,
- },
- },
- iconName: 'back',
- title: 'Folder Name',
- // todo use history back
- },
- {
- id: 'note',
- href: {
- pathname: '/notes',
- query: {
- action: 'new',
- parentFolderId: '00000000-0000-0000-000000000000',
- },
- },
- iconName: 'new-note',
- title: 'Create Note',
- },
- {
- id: 'folder',
- href: {
- pathname: '/folders',
- query: {
- action: 'new',
- parentFolderId: '00000000-0000-0000-000000000000',
- },
- },
- iconName: 'new-folder',
- title: 'Create Child Folder',
- },
- {
- id: 'map',
- href: {
- pathname: '/notes',
- query: {
- action: 'view-map',
- parentFolderId: '00000000-0000-0000-000000000000',
- },
- },
- iconName: 'mind-map',
- title: 'View Folder Mind Map',
- },
- ]}
- secondaryItems={
- Array.isArray(notes!)
- ? notes.map(n => ({
- id: n.id,
- active: n.id === id,
- href: {
- pathname: '/notes/[id]',
- query: { id: n.id },
- },
- iconName: 'note',
- replace: true,
- title: n.title.trim(),
- subtitle: (
- <time
- dateTime={new Date(n.updatedAt).toISOString()}
- >
- {formatDate(new Date(n.updatedAt))}
- </time>
- ),
- actions: [
- {
- id: 'bin',
- iconName: 'bin',
- onClick: Note.remove({ setNotes, notes, router, })(n),
- }
- ],
- }))
- : []
- }
- />
- <Main>
- <Container>
- {
- Array.isArray(notes!)
- && (
- <React.Fragment>
- <PostPrimary>
- <TitleInput
- placeholder="Title"
- value={title}
- onChange={Note.updateTitle({
- stateRef,
- timeoutRef,
- router,
- id,
- setNotes,
- setTitle,
- })}
- />
- <PostMeta>
- {
- stateRef.current.updatedAt
- && router.query.id
- && (
- <time
- dateTime={new Date(stateRef.current.updatedAt).toISOString()}
- >
- Last updated {formatDate(new Date(stateRef.current.updatedAt))}
- </time>
- )
- }
- </PostMeta>
- </PostPrimary>
- <Editor
- autoFocus={false}
- key={id}
- content={stateRef.current ? stateRef.current.content : undefined}
- onChange={Note.updateContent({
- stateRef,
- timeoutRef,
- router,
- id,
- setNotes,
- })}
- placeholder="Start typing here..."
- />
- </React.Fragment>
- )
- }
- </Container>
- </Main>
- </React.Fragment>
- )
- }
-
- export const getServerSideProps = async ctx => {
- if (ctx.params) {
- return {
- props: {
- id: ctx.params?.id
- }
- }
- }
-
- return {
- props: {}
- }
- }
-
- export default Notes
|