diff --git a/client/src/App.jsx b/client/src/App.jsx index c4c599ae..cc6507e2 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -2,6 +2,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; import Landing from '/src/landing/Landing.jsx'; import Page from '/src/page/Page.jsx'; +import PageWithSidebar from '/src/page/PageWithSidebar.jsx'; import HistoryView from '/src/page/HistoryView.jsx'; import LogIn from '/src/login/LogIn.jsx'; import Register from '/src/login/Register.jsx'; @@ -22,8 +23,8 @@ function App() { }/> }/> }/> - }/> - }/> + }/> + }/> }/> }/> }/> diff --git a/client/src/logo.svg b/client/src/logo.svg deleted file mode 100644 index 9dfc1c05..00000000 --- a/client/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/page/CommandEntry.css b/client/src/page/CommandEntry.css new file mode 100644 index 00000000..e720726d --- /dev/null +++ b/client/src/page/CommandEntry.css @@ -0,0 +1,21 @@ +.commandline { + margin-top: 2rem; + margin-bottom: 2rem; + margin-left: auto; + margin-right: auto; + background: lightblue; + position: fixed; + bottom: 0; + left: 20%; + right: 20%; + +} +.commandline input { + font-size: 16pt; + border: none; + padding: 1rem; + width: calc(100% - 2rem); + margin-left: 0; + margin-right: 0; + background: transparent; +} \ No newline at end of file diff --git a/client/src/page/CommandEntry.jsx b/client/src/page/CommandEntry.jsx new file mode 100644 index 00000000..d1f3d20b --- /dev/null +++ b/client/src/page/CommandEntry.jsx @@ -0,0 +1,13 @@ +import { useState } from 'react'; + +import './CommandEntry.css'; + +function CommandEntry({command, onChange}) { + return ( +
+ +
+ ); +} + +export default CommandEntry; \ No newline at end of file diff --git a/client/src/page/Page.jsx b/client/src/page/Page.jsx index d909164c..6986fd45 100644 --- a/client/src/page/Page.jsx +++ b/client/src/page/Page.jsx @@ -63,7 +63,7 @@ function Page({ editing }) {

🌳 - {pagenumber}. + {pagenumber}.  diff --git a/client/src/page/PageWithSidebar.jsx b/client/src/page/PageWithSidebar.jsx index e69de29b..5b3323b0 100644 --- a/client/src/page/PageWithSidebar.jsx +++ b/client/src/page/PageWithSidebar.jsx @@ -0,0 +1,128 @@ +import { useState } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useParams, useNavigate } from 'react-router-dom'; +import { apiUrl, fetchPage, fetchPageAtEdit, postPage, deletePage } from '../apiTools.jsx'; +import { useFixLinks } from '../clientStuff.jsx'; +import { useLoggedIn } from '../AuthProvider.jsx'; +import Sidebar from './Sidebar.jsx'; +import CommandEntry from './CommandEntry.jsx'; + +import './Pages.css'; + +function PageWithSidebar({ editing }) { + const queryClient = useQueryClient(); + const navigate = useNavigate(); + const { pagenumber, editid } = useParams(); + const loggedIn = useLoggedIn(); + const noLoad = useFixLinks(); + const [command, setCommand] = useState(""); + + const fetchQuery = useQuery({ // fetch the currrent values + queryKey: ['page', pagenumber, editid], + queryFn: () => editid ? fetchPageAtEdit(pagenumber, editid) : fetchPage(pagenumber) + }) + + const postMutation = useMutation({ // for changing the value when we're done with it + mutationFn: ({id, title, description}) => postPage({id, title, description}), + onSettled: async (data, error, variables) => { + // Invalidate and refetch + await queryClient.invalidateQueries({ queryKey: ['page', variables.id, undefined] }) + }, + }); + + const deleteMutation = useMutation({ // for changing the value when we're done with it + mutationFn: (id) => deletePage(id), + onSettled: async (data, error, variables) => { + // Invalidate and refetch + await queryClient.invalidateQueries({ queryKey: ['pages'] }) + }, + }); + + const readyToShow = !(fetchQuery.error || fetchQuery.isPending); + + let {id, title, description, html, time, author} = fetchQuery.data || {}; + if (!title) title = "[no title]"; + if (!html) html = "[body missing]"; + if (!description) description = "[body missing]"; + + function submitChanges(e) { + const newTitle = document.querySelector('span').innerHTML; + const newText = document.querySelector('pre').innerHTML; + postMutation.mutate({ + id: pagenumber, + title: newTitle, + description: newText + }); + navigate(`/${pagenumber}`, {replace: true}) + } + + function submitDelete(e) { + e.preventDefault(); + deleteMutation.mutate(pagenumber); + navigate(`/`); + } + + return ( + <> +
+
+

+ 🌳 + {pagenumber}.  + +

+ {readyToShow && editid && `saved at ${time} by user #${author}`} +
+
+
+ { readyToShow ? + ( + editing ? +
+                :
+                
+ ) + : + "..." + } +
+ + {editing && ( + )} + {!editing && !editid && ( + )} + {loggedIn && ( + )} +
+ + setCommand(e.target.value)}/> + + ); +} + +export default PageWithSidebar; \ No newline at end of file diff --git a/client/src/page/Sidebar.css b/client/src/page/Sidebar.css new file mode 100644 index 00000000..a024afc9 --- /dev/null +++ b/client/src/page/Sidebar.css @@ -0,0 +1,25 @@ +.sidebar { + transition: all 0.1s linear; + margin: 0; + background: lightblue; + position: fixed; + width: 30ch; + height: 100%; + right: 0; + top: 0; +} +.sidebar-hidden { + transform: translateX(20ch); +} + +.sidebar li { + list-style: none; +} + +.sidebar li button { + text-transform: uppercase; +} + +.sidebar-hidden li { + display: none; +} \ No newline at end of file diff --git a/client/src/page/Sidebar.jsx b/client/src/page/Sidebar.jsx new file mode 100644 index 00000000..88352d09 --- /dev/null +++ b/client/src/page/Sidebar.jsx @@ -0,0 +1,29 @@ +import { useState } from 'react'; +import { useLoggedIn } from '../AuthProvider.jsx'; + +import './Sidebar.css'; + +function Sidebar({children, pagenumber, hidden=false, sendWord=(()=>null)}) { + const [open, setOpen] = useState(!hidden); + const loggedIn = useLoggedIn(); + + const verbs = ["go", "take"]; + + return ( +
+ +
    + {verbs.map( (name) => ( +
  • + +
  • + ) )} + {children} +
+
+ ); +} + +export default Sidebar; \ No newline at end of file