diff options
Diffstat (limited to 'client/src/routes/app')
-rw-r--r-- | client/src/routes/app/app.css | 9 | ||||
-rw-r--r-- | client/src/routes/app/app.jsx | 98 | ||||
-rw-r--r-- | client/src/routes/app/components/content/content.css | 20 | ||||
-rw-r--r-- | client/src/routes/app/components/content/content.jsx | 32 | ||||
-rw-r--r-- | client/src/routes/app/components/sidebar/sidebar.css | 24 | ||||
-rw-r--r-- | client/src/routes/app/components/sidebar/sidebar.jsx | 19 |
6 files changed, 202 insertions, 0 deletions
diff --git a/client/src/routes/app/app.css b/client/src/routes/app/app.css new file mode 100644 index 0000000..bccae8f --- /dev/null +++ b/client/src/routes/app/app.css @@ -0,0 +1,9 @@ +.app { + display: flex; + + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; +} diff --git a/client/src/routes/app/app.jsx b/client/src/routes/app/app.jsx new file mode 100644 index 0000000..67dcd91 --- /dev/null +++ b/client/src/routes/app/app.jsx @@ -0,0 +1,98 @@ +import {useEffect, useRef, useState} from 'react'; +import { useLocation, useParams } from "react-router"; + +import './app.css'; + +import Sidebar from './components/sidebar/sidebar'; +import Content from './components/content/content'; + +const files = [ + { + id: '1', + title: 'kaas', + items: [ + { type: 'plain', text: 'kaas 1' }, + { type: 'plain', text: 'kaas 2' }, + { type: 'plain', text: 'kaas 3' }, + { type: 'plain', text: 'kaas 4' }, + { type: 'plain', text: 'kaas 5' }, + ], + }, + { + id: '2', + title: 'ham', + items: [ + { type: 'plain', text: 'ham 1' }, + { type: 'plain', text: 'ham 2' }, + { type: 'plain', text: 'ham 3' }, + { type: 'plain', text: 'ham 4' }, + { type: 'plain', text: 'ham 5' }, + ], + }, + { + id: '3', + title: 'vis', + items: [ + { type: 'plain', text: 'vis 1' }, + { type: 'plain', text: 'vis 2' }, + { type: 'plain', text: 'vis 3' }, + { type: 'plain', text: 'vis 4' }, + { type: 'plain', text: 'vis 5' }, + ], + }, + { + id: '4', + title: 'empty', + items: [ + { type: 'plain', text: '' }, + ], + + children: [{ + id: '4/5', + title: 'empty 2', + items: [ + { type: 'plain', text: '' }, + ], + }], + }, +] + +function splitOnce(str, sep) { + const idx = str.indexOf(sep); + if (idx === -1) return [str, '']; + + return [ str.slice(0, idx), str.slice(idx+1) ]; +} + +export default function App() { + const e = useLocation(); + const fullPath = e.pathname.replace('/file/', ''); + let path = fullPath; + + let cur = { children: files }; + let builtKey = ''; + while (path != '') { + let key; + [key, path] = splitOnce(path, '/'); + builtKey += `/${key}`; + + console.log(key, path, cur); + cur = (cur.children ?? []).find(p => p.id === builtKey.slice(1)); + } + + const file = cur; + const [title, setTitle] = useState(() => file.title); + const [items, setItems] = useState(() => file.items); + + useEffect(() => { + setTitle(() => file.title); + setItems(() => file.items); + + document.title = '🧀🥜 ' + file.title; + }, [fullPath]); + + return <div className='app'> + <Sidebar files={files} /> + <Content title={title} items={items} setTitle={setTitle} setItems={setItems} /> + </div> +} diff --git a/client/src/routes/app/components/content/content.css b/client/src/routes/app/components/content/content.css new file mode 100644 index 0000000..196fb96 --- /dev/null +++ b/client/src/routes/app/components/content/content.css @@ -0,0 +1,20 @@ +.content { + display: flex; + flex-direction: column; + + flex-grow: 1; + padding: 10px; + + overflow-y: scroll; + + .title { + border: 0; + padding: 10px; + margin-left: 15px; + margin-bottom: 50px; + } + .title:focus { + border: 0; + outline: 0; + } +} diff --git a/client/src/routes/app/components/content/content.jsx b/client/src/routes/app/components/content/content.jsx new file mode 100644 index 0000000..42ecb8a --- /dev/null +++ b/client/src/routes/app/components/content/content.jsx @@ -0,0 +1,32 @@ +import {useLayoutEffect, useRef, useState} from 'react'; + +import './content.css'; + +import Entry from '../../../../components/entry'; + +export default function Content({ title, setTitle, items, setItems }) { + const [focused, setFocused] = useState(null); + + const children = items.map((item, i) => { + return <Entry + item={item} + isFocused={i === focused} + onSelect={delta => setFocused(i + delta)} + onRemove={refocus => setItems(a => { + if (refocus) { + setFocused(i-1); + } + return [...a.slice(0, i), ...a.slice(i + 1)] + })} + onEnter={type => setItems(a => { + setFocused(i+1); + return a.toSpliced(i+1, 0, { type, text: '' }); + })} + />; + }); + + return <div className="content"> + <h1 className='title' contentEditable="true">{title}</h1> + {children} + </div>; +} diff --git a/client/src/routes/app/components/sidebar/sidebar.css b/client/src/routes/app/components/sidebar/sidebar.css new file mode 100644 index 0000000..515117a --- /dev/null +++ b/client/src/routes/app/components/sidebar/sidebar.css @@ -0,0 +1,24 @@ +.sidebar { + width: 200px; + background-color: #f2f2f2; + + flex-shrink: 0; + + h1 { + margin-left: 10px; + margin-top: 10px; + } + + .file { + display: block; + + color: black; + text-decoration: none; + + padding: 5px; + } + + .file:hover { + background-color: #e4e4e4; + } +} diff --git a/client/src/routes/app/components/sidebar/sidebar.jsx b/client/src/routes/app/components/sidebar/sidebar.jsx new file mode 100644 index 0000000..1ce7d2b --- /dev/null +++ b/client/src/routes/app/components/sidebar/sidebar.jsx @@ -0,0 +1,19 @@ +import { useNavigate } from "react-router"; +import { RichTreeView } from '@mui/x-tree-view/RichTreeView'; + +import './sidebar.css'; + + +export default function Sidebar({ files }) { + const navigate = useNavigate(); + + const onSelect = (_, i) => { + navigate(`/file/${i}`); + }; + + return <div className="sidebar"> + <h1>🧀🥜</h1> + <hr/> + <RichTreeView items={files} onItemClick={onSelect} getItemLabel={p => p.title} /> + </div>; +} |