summaryrefslogtreecommitdiff
path: root/client/src/routes
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/routes')
-rw-r--r--client/src/routes/app/app.css9
-rw-r--r--client/src/routes/app/app.jsx98
-rw-r--r--client/src/routes/app/components/content/content.css20
-rw-r--r--client/src/routes/app/components/content/content.jsx32
-rw-r--r--client/src/routes/app/components/sidebar/sidebar.css24
-rw-r--r--client/src/routes/app/components/sidebar/sidebar.jsx19
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>;
+}