diff --git a/app/package.json b/app/package.json
index 79aabaf..4176401 100644
--- a/app/package.json
+++ b/app/package.json
@@ -18,7 +18,11 @@
"@tanstack/react-query": "^5.37.1",
"@tauri-apps/api": "^1",
"@uiw/react-md-editor": "^4.0.4",
+ "hast-util-to-mdast": "^10.1.0",
"javascript-time-ago": "^2.5.10",
+ "jotai": "^2.8.1",
+ "mdast-util-from-markdown": "^2.0.0",
+ "mdast-util-to-markdown": "^2.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^9.0.1",
diff --git a/app/src/components/Header.module.scss b/app/src/components/Header.module.scss
index 9804ffb..f6eb526 100644
--- a/app/src/components/Header.module.scss
+++ b/app/src/components/Header.module.scss
@@ -2,7 +2,7 @@
display: flex;
align-items: center;
- padding: 12px;
+ padding: 2px 12px;
gap: 12px;
background: rgb(204, 201, 255);
diff --git a/app/src/components/Header.tsx b/app/src/components/Header.tsx
index c573206..a88315c 100644
--- a/app/src/components/Header.tsx
+++ b/app/src/components/Header.tsx
@@ -1,10 +1,14 @@
import styles from "./Header.module.scss";
+import NoteAddIcon from "@mui/icons-material/NoteAdd";
import SearchBar from "./SearchBar";
export default function Header() {
return (
{isSuccess ? (
@@ -42,49 +46,23 @@ export default function NodeDisplay({ id }: NodeDisplayProps) {
function NodeDisplayHeaderLoaded({ id, data }) {
return (
-
+ <>
Type {data.type} · Last updated{" "}
· {id}
-
+ >
);
}
function NodeDisplayLoaded({ id, data }) {
- const [value, setValue] = useState(() => data.content);
- const [isEditing, setIsEditing] = useState(() => false);
- return (
- <>
-
- JSON
- {JSON.stringify(data, null, 2)}
-
+ switch (data.type) {
+ case "panorama/journal/page":
+ return
;
-
-
-
- {
- isEditing ? (
- <>
-
- >
- ) : (
- <>
-
- >
- )
- // {data.content}
- }
-
- >
- );
+ default:
+ return (
+ <>
+ Don't know how to render node of type
{data.type}
+ >
+ );
+ }
}
diff --git a/app/src/components/SearchBar.module.scss b/app/src/components/SearchBar.module.scss
index df61ce4..b802f46 100644
--- a/app/src/components/SearchBar.module.scss
+++ b/app/src/components/SearchBar.module.scss
@@ -2,8 +2,20 @@
background-color: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(10px);
- // box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.25);
+ box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.25);
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
min-width: 500px;
min-height: 200px;
+
+ padding: 12px;
+}
+
+.entry {
+ padding: 2px 6px;
+ font-size: 14pt;
+ border-radius: 4px;
+ border: none;
+ outline: none;
}
\ No newline at end of file
diff --git a/app/src/components/SearchBar.tsx b/app/src/components/SearchBar.tsx
index 4b00259..9d81ebb 100644
--- a/app/src/components/SearchBar.tsx
+++ b/app/src/components/SearchBar.tsx
@@ -33,6 +33,7 @@ export default function SearchBar() {
<>
setShowMenu(true)}
@@ -44,7 +45,6 @@ export default function SearchBar() {
{showMenu && (
- {/* */}
- {/* */}
)}
@@ -61,6 +60,6 @@ export default function SearchBar() {
);
}
-function SearchMenu({}) {
- return <>Search>;
+function SearchMenu() {
+ return <>Search suggestions...>;
}
diff --git a/app/src/components/nodes/JournalPage.module.scss b/app/src/components/nodes/JournalPage.module.scss
new file mode 100644
index 0000000..3622f1f
--- /dev/null
+++ b/app/src/components/nodes/JournalPage.module.scss
@@ -0,0 +1,9 @@
+.mdContent {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+}
+
+.mdEditor {
+ flex-grow: 1;
+}
\ No newline at end of file
diff --git a/app/src/components/nodes/JournalPage.tsx b/app/src/components/nodes/JournalPage.tsx
new file mode 100644
index 0000000..84eef03
--- /dev/null
+++ b/app/src/components/nodes/JournalPage.tsx
@@ -0,0 +1,29 @@
+import { createContext, useCallback, useContext, useState } from "react";
+import styles from "./JournalPage.module.scss";
+import MDEditor from "@uiw/react-md-editor";
+import Markdown from "react-markdown";
+import { toMdast } from "hast-util-to-mdast";
+import { fromMarkdown } from "mdast-util-from-markdown";
+import { toMarkdown } from "mdast-util-to-markdown";
+
+const MDContext = createContext(null);
+
+export default function JournalPage({ id, data }) {
+ const [content, setContent] = useState(() => data.content);
+ const [isEditing, setIsEditing] = useState(() => false);
+
+ const tree = fromMarkdown(data.content);
+ console.log("tree", tree);
+
+ const contextValue = { content, setContent, isEditing, setIsEditing };
+ return (
+ <>
+
+ JSON
+ {JSON.stringify(data, null, 2)}
+
+
+
+ >
+ );
+}
diff --git a/crates/panorama-daemon/src/main.rs b/crates/panorama-daemon/src/main.rs
index 5428416..10948ec 100644
--- a/crates/panorama-daemon/src/main.rs
+++ b/crates/panorama-daemon/src/main.rs
@@ -29,7 +29,7 @@ use tower_http::cors::{self, CorsLayer};
use crate::{
journal::get_todays_journal_id,
migrations::run_migrations,
- node::{get_node, update_node},
+ node::{get_node, node_types, update_node},
};
#[derive(Clone)]
@@ -66,12 +66,13 @@ async fn main() -> Result<()> {
.route("/", get(|| async { "Hello, World!" }))
.route("/node/:id", get(get_node))
.route("/node/:id", post(update_node))
+ .route("/node/types", get(node_types))
.route("/journal/get_todays_journal_id", get(get_todays_journal_id))
.layer(ServiceBuilder::new().layer(cors))
.with_state(state);
let listener = TcpListener::bind("0.0.0.0:5195").await?;
- println!("Listening...");
+ println!("Listening... {:?}", listener);
axum::serve(listener, app).await?;
Ok(())
diff --git a/crates/panorama-daemon/src/node.rs b/crates/panorama-daemon/src/node.rs
index 9fa6a16..c1f4664 100644
--- a/crates/panorama-daemon/src/node.rs
+++ b/crates/panorama-daemon/src/node.rs
@@ -1,3 +1,5 @@
+use std::collections::HashMap;
+
use axum::{
extract::{Path, State},
http::StatusCode,
@@ -54,12 +56,26 @@ pub async fn get_node(
))
}
-#[derive(Deserialize)]
-struct NodeUpdate {}
+#[derive(Deserialize, Debug)]
+pub struct UpdateData {
+ title: Option
,
+ extra_data: Option>,
+}
pub async fn update_node(
State(state): State,
Path(node_id): Path,
+ Json(update_data): Json,
) -> AppResult> {
+ println!("Update data: {:?}", update_data);
+
Ok(Json(json!({})))
}
+
+pub async fn node_types() -> AppResult> {
+ Ok(Json(json!({
+ "types": [
+ { "id": "panorama/journal/page", "display": "Journal Entry" },
+ ]
+ })))
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a8cf89d..b2b0c4a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,9 +35,21 @@ importers:
'@uiw/react-md-editor':
specifier: ^4.0.4
version: 4.0.4(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ hast-util-to-mdast:
+ specifier: ^10.1.0
+ version: 10.1.0
javascript-time-ago:
specifier: ^2.5.10
version: 2.5.10
+ jotai:
+ specifier: ^2.8.1
+ version: 2.8.1(@types/react@18.3.3)(react@18.3.1)
+ mdast-util-from-markdown:
+ specifier: ^2.0.0
+ version: 2.0.0
+ mdast-util-to-markdown:
+ specifier: ^2.1.0
+ version: 2.1.0
react:
specifier: ^18.2.0
version: 18.3.1
@@ -954,6 +966,9 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
+ hast-util-embedded@3.0.0:
+ resolution: {integrity: sha512-naH8sld4Pe2ep03qqULEtvYr7EjrLK2QHY8KJR6RJkTUjPGObe1vnx585uzem2hGra+s1q08DZZpfgDVYRbaXA==}
+
hast-util-from-html@2.0.1:
resolution: {integrity: sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==}
@@ -966,6 +981,9 @@ packages:
hast-util-heading-rank@3.0.0:
resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==}
+ hast-util-is-body-ok-link@3.0.0:
+ resolution: {integrity: sha512-VFHY5bo2nY8HiV6nir2ynmEB1XkxzuUffhEGeVx7orbu/B1KaGyeGgMZldvMVx5xWrDlLLG/kQ6YkJAMkBEx0w==}
+
hast-util-is-element@3.0.0:
resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==}
@@ -975,6 +993,9 @@ packages:
hast-util-parse-selector@4.0.0:
resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==}
+ hast-util-phrasing@3.0.1:
+ resolution: {integrity: sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ==}
+
hast-util-raw@9.0.3:
resolution: {integrity: sha512-ICWvVOF2fq4+7CMmtCPD5CM4QKjPbHpPotE6+8tDooV0ZuyJVUzHsrNX+O5NaRbieTf0F7FfeBOMAwi6Td0+yQ==}
@@ -987,12 +1008,18 @@ packages:
hast-util-to-jsx-runtime@2.3.0:
resolution: {integrity: sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==}
+ hast-util-to-mdast@10.1.0:
+ resolution: {integrity: sha512-DsL/SvCK9V7+vfc6SLQ+vKIyBDXTk2KLSbfBYkH4zeF/uR1yBajHRhkzuaUSGOB1WJSTieJBdHwxlC+HLKvZZw==}
+
hast-util-to-parse5@8.0.0:
resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==}
hast-util-to-string@3.0.0:
resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==}
+ hast-util-to-text@4.0.2:
+ resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==}
+
hast-util-whitespace@3.0.0:
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
@@ -1062,6 +1089,18 @@ packages:
javascript-time-ago@2.5.10:
resolution: {integrity: sha512-EUxp4BP74QH8xiYHyeSHopx1XhMMJ9qEX4rcBdFtpVWmKRdzpxbNzz2GSbuekZr5wt0rmLehuyp0PE34EAJT9g==}
+ jotai@2.8.1:
+ resolution: {integrity: sha512-Gmk5Y3yJL/vN5S0rQ6AaWpXH5Q+HBGHThMHXfylVzXGVuO8YxPRtZf8Y9XYvl+h7ZMQXoHNdFi37vNsJFsiszQ==}
+ engines: {node: '>=12.20.0'}
+ peerDependencies:
+ '@types/react': '>=17.0.0'
+ react: '>=17.0.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ react:
+ optional: true
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -1357,6 +1396,9 @@ packages:
resolution: {integrity: sha512-BpAT/3lU9DMJ2siYVD/dSR0A/zQgD6Fb+fxkJd4j+wDVy6TYbYpK+FZqu8eM9EuNKGvi4BJR7XTZ/+zF02Dq8w==}
engines: {node: '>=16'}
+ rehype-minify-whitespace@6.0.0:
+ resolution: {integrity: sha512-i9It4YHR0Sf3GsnlR5jFUKXRr9oayvEk9GKQUkwZv6hs70OH9q3OCZrq9PpLvIGKt3W+JxBOxCidNVpH/6rWdA==}
+
rehype-parse@9.0.0:
resolution: {integrity: sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==}
@@ -1465,6 +1507,9 @@ packages:
trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
+ trim-trailing-lines@2.1.0:
+ resolution: {integrity: sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg==}
+
trough@2.2.0:
resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==}
@@ -1479,6 +1524,9 @@ packages:
unist-util-filter@5.0.1:
resolution: {integrity: sha512-pHx7D4Zt6+TsfwylH9+lYhBhzyhEnCXs/lbq/Hstxno5z4gVdyc2WEW0asfjGKPyG4pEKrnBv5hdkO6+aRnQJw==}
+ unist-util-find-after@5.0.0:
+ resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==}
+
unist-util-is@6.0.0:
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
@@ -2388,6 +2436,11 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ hast-util-embedded@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-is-element: 3.0.0
+
hast-util-from-html@2.0.1:
dependencies:
'@types/hast': 3.0.4
@@ -2416,6 +2469,10 @@ snapshots:
dependencies:
'@types/hast': 3.0.4
+ hast-util-is-body-ok-link@3.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+
hast-util-is-element@3.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -2428,6 +2485,14 @@ snapshots:
dependencies:
'@types/hast': 3.0.4
+ hast-util-phrasing@3.0.1:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-embedded: 3.0.0
+ hast-util-has-property: 3.0.0
+ hast-util-is-body-ok-link: 3.0.0
+ hast-util-is-element: 3.0.0
+
hast-util-raw@9.0.3:
dependencies:
'@types/hast': 3.0.4
@@ -2498,6 +2563,23 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ hast-util-to-mdast@10.1.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/mdast': 4.0.4
+ '@ungap/structured-clone': 1.2.0
+ hast-util-phrasing: 3.0.1
+ hast-util-to-html: 9.0.1
+ hast-util-to-text: 4.0.2
+ hast-util-whitespace: 3.0.0
+ mdast-util-phrasing: 4.1.0
+ mdast-util-to-hast: 13.1.0
+ mdast-util-to-string: 4.0.0
+ rehype-minify-whitespace: 6.0.0
+ trim-trailing-lines: 2.1.0
+ unist-util-position: 5.0.0
+ unist-util-visit: 5.0.0
+
hast-util-to-parse5@8.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -2512,6 +2594,13 @@ snapshots:
dependencies:
'@types/hast': 3.0.4
+ hast-util-to-text@4.0.2:
+ dependencies:
+ '@types/hast': 3.0.4
+ '@types/unist': 3.0.2
+ hast-util-is-element: 3.0.0
+ unist-util-find-after: 5.0.0
+
hast-util-whitespace@3.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -2584,6 +2673,11 @@ snapshots:
dependencies:
relative-time-format: 1.1.6
+ jotai@2.8.1(@types/react@18.3.3)(react@18.3.1):
+ optionalDependencies:
+ '@types/react': 18.3.3
+ react: 18.3.1
+
js-tokens@4.0.0: {}
jsesc@2.5.2: {}
@@ -3108,6 +3202,14 @@ snapshots:
unified: 11.0.4
unist-util-visit: 5.0.0
+ rehype-minify-whitespace@6.0.0:
+ dependencies:
+ '@types/hast': 3.0.4
+ hast-util-embedded: 3.0.0
+ hast-util-is-element: 3.0.0
+ hast-util-whitespace: 3.0.0
+ unist-util-is: 6.0.0
+
rehype-parse@9.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -3271,6 +3373,8 @@ snapshots:
trim-lines@3.0.1: {}
+ trim-trailing-lines@2.1.0: {}
+
trough@2.2.0: {}
typescript@5.4.5: {}
@@ -3291,6 +3395,11 @@ snapshots:
unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1
+ unist-util-find-after@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.2
+ unist-util-is: 6.0.0
+
unist-util-is@6.0.0:
dependencies:
'@types/unist': 3.0.2