Compare commits
2 Commits
06daa25c5a
...
80d5f76840
Author | SHA1 | Date | |
---|---|---|---|
|
80d5f76840 | ||
|
e24ea90806 |
0
scribe/.gitignore → notes/.gitignore
vendored
BIN
notes/bun.lockb
Executable file
@ -4,9 +4,8 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="stylesheet" href="/src/styles.css" />
|
<link rel="stylesheet" href="/src/styles.css" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Tauri App</title>
|
<title>Notes</title>
|
||||||
<script type="module" src="/src/main.ts" defer></script>
|
<script type="module" src="/src/main.tsx" defer></script>
|
||||||
<script type="module" src="/src/prosemirror.ts" defer></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@ -33,6 +32,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<p>Click on the Tauri logo to learn more about the framework</p>
|
<p>Click on the Tauri logo to learn more about the framework</p>
|
||||||
|
<div id="editor"></div>
|
||||||
|
|
||||||
<form class="row" id="greet-form">
|
<form class="row" id="greet-form">
|
||||||
<input id="greet-input" placeholder="Enter a name..." />
|
<input id="greet-input" placeholder="Enter a name..." />
|
||||||
@ -41,7 +41,5 @@
|
|||||||
<p id="greet-msg"></p>
|
<p id="greet-msg"></p>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<div id="editor"></div>
|
|
||||||
<div id="content">test</div>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "scribe",
|
"name": "notes",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@ -10,13 +10,11 @@
|
|||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/react": "^11.13.3",
|
||||||
|
"@emotion/styled": "^11.13.0",
|
||||||
|
"@mui/material": "^6.1.7",
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-shell": "^2",
|
"@tauri-apps/plugin-shell": "^2"
|
||||||
"prosemirror-example-setup": "^1.2.3",
|
|
||||||
"prosemirror-schema-basic": "^1.2.3",
|
|
||||||
"prosemirror-schema-list": "^1.4.1",
|
|
||||||
"prosemirror-state": "^1.4.3",
|
|
||||||
"prosemirror-view": "^1.34.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "^2",
|
"@tauri-apps/cli": "^2",
|
611
scribe/src-tauri/Cargo.lock → notes/src-tauri/Cargo.lock
generated
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scribe"
|
name = "notes"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "A Tauri App"
|
description = "A Tauri App"
|
||||||
authors = ["you"]
|
authors = ["you"]
|
||||||
@ -11,7 +11,7 @@ edition = "2021"
|
|||||||
# The `_lib` suffix may seem redundant but it is necessary
|
# The `_lib` suffix may seem redundant but it is necessary
|
||||||
# to make the lib name unique and wouldn't conflict with the bin name.
|
# to make the lib name unique and wouldn't conflict with the bin name.
|
||||||
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
||||||
name = "scribe_lib"
|
name = "notes_lib"
|
||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 974 B After Width: | Height: | Size: 974 B |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 903 B |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -2,5 +2,5 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
scribe_lib::run()
|
notes_lib::run()
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "scribe",
|
"productName": "notes",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"identifier": "com.scribe.app",
|
"identifier": "com.notes.app",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "bun run dev",
|
"beforeDevCommand": "bun run dev",
|
||||||
"devUrl": "http://localhost:1420",
|
"devUrl": "http://localhost:1420",
|
||||||
@ -13,7 +13,7 @@
|
|||||||
"withGlobalTauri": true,
|
"withGlobalTauri": true,
|
||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
"title": "scribe",
|
"title": "notes",
|
||||||
"width": 800,
|
"width": 800,
|
||||||
"height": 600
|
"height": 600
|
||||||
}
|
}
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
138
notes/src/claude-generated-code.tsx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import Card from '@mui/material/Card';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
import {
|
||||||
|
Bold,
|
||||||
|
Italic,
|
||||||
|
List,
|
||||||
|
ListOrdered,
|
||||||
|
Heading1,
|
||||||
|
Heading2,
|
||||||
|
Quote,
|
||||||
|
MoreVertical,
|
||||||
|
X
|
||||||
|
} from 'lucide-react';
|
||||||
|
|
||||||
|
const NoteEditor = () => {
|
||||||
|
const [content, setContent] = useState('');
|
||||||
|
const [isToolbarOpen, setIsToolbarOpen] = useState(false);
|
||||||
|
const [viewportHeight, setViewportHeight] = useState('100vh');
|
||||||
|
|
||||||
|
// Handle viewport resize when keyboard appears
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
const visualViewport = window.visualViewport;
|
||||||
|
if (visualViewport) {
|
||||||
|
setViewportHeight(`${visualViewport.height}px`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.visualViewport?.addEventListener('resize', handleResize);
|
||||||
|
window.visualViewport?.addEventListener('scroll', handleResize);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.visualViewport?.removeEventListener('resize', handleResize);
|
||||||
|
window.visualViewport?.removeEventListener('scroll', handleResize);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const execCommand = (command, value = false) => {
|
||||||
|
document.execCommand(command, false, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ToolbarButton = ({ icon: Icon, command, value, label }) => (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="lg"
|
||||||
|
className="p-4 h-auto flex flex-col items-center gap-1"
|
||||||
|
onClick={() => {
|
||||||
|
execCommand(command, value);
|
||||||
|
// Don't close toolbar for formatting commands
|
||||||
|
if (command === 'save') setIsToolbarOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon className="w-6 h-6" />
|
||||||
|
<span className="text-xs">{label}</span>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 flex flex-col"
|
||||||
|
style={{ height: viewportHeight }}
|
||||||
|
>
|
||||||
|
{/* Main toolbar button */}
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="fixed top-2 right-2 z-20"
|
||||||
|
onClick={() => setIsToolbarOpen(!isToolbarOpen)}
|
||||||
|
>
|
||||||
|
{isToolbarOpen ? <X className="w-4 h-4" /> : <MoreVertical className="w-4 h-4" />}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{/* Expandable toolbar */}
|
||||||
|
{isToolbarOpen && (
|
||||||
|
<Card className="absolute top-12 right-2 z-10 p-2 shadow-lg">
|
||||||
|
<div className="grid grid-cols-3 gap-2">
|
||||||
|
<ToolbarButton
|
||||||
|
icon={Bold}
|
||||||
|
command="bold"
|
||||||
|
label="Bold"
|
||||||
|
/>
|
||||||
|
<ToolbarButton
|
||||||
|
icon={Italic}
|
||||||
|
command="italic"
|
||||||
|
label="Italic"
|
||||||
|
/>
|
||||||
|
<ToolbarButton
|
||||||
|
icon={List}
|
||||||
|
command="insertUnorderedList"
|
||||||
|
label="Bullet List"
|
||||||
|
/>
|
||||||
|
<ToolbarButton
|
||||||
|
icon={ListOrdered}
|
||||||
|
command="insertOrderedList"
|
||||||
|
label="Numbered List"
|
||||||
|
/>
|
||||||
|
<ToolbarButton
|
||||||
|
icon={Heading1}
|
||||||
|
command="formatBlock"
|
||||||
|
value="<h1>"
|
||||||
|
label="Heading 1"
|
||||||
|
/>
|
||||||
|
<ToolbarButton
|
||||||
|
icon={Heading2}
|
||||||
|
command="formatBlock"
|
||||||
|
value="<h2>"
|
||||||
|
label="Heading 2"
|
||||||
|
/>
|
||||||
|
<ToolbarButton
|
||||||
|
icon={Quote}
|
||||||
|
command="formatBlock"
|
||||||
|
value="<blockquote>"
|
||||||
|
label="Quote"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Editor area */}
|
||||||
|
<div className="flex-1 overflow-auto">
|
||||||
|
<div
|
||||||
|
className="min-h-full p-4 focus:outline-none"
|
||||||
|
contentEditable={true}
|
||||||
|
onInput={(e) => setContent(e.currentTarget.innerHTML)}
|
||||||
|
suppressContentEditableWarning={true}
|
||||||
|
style={{
|
||||||
|
WebkitUserSelect: 'text',
|
||||||
|
WebkitTouchCallout: 'none',
|
||||||
|
overflowY: 'auto',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NoteEditor;
|
32
notes/src/main.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
import NoteEditor from "./claude-generated-code";
|
||||||
|
|
||||||
|
const domElem = document.getElementById("editor");
|
||||||
|
console.log(domElem);
|
||||||
|
const root = createRoot(domElem);
|
||||||
|
root.render(<NoteEditor/>);
|
||||||
|
|
||||||
|
let greetInputEl: HTMLInputElement | null;
|
||||||
|
let greetMsgEl: HTMLElement | null;
|
||||||
|
|
||||||
|
async function greet() {
|
||||||
|
if (greetMsgEl && greetInputEl) {
|
||||||
|
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||||
|
greetMsgEl.textContent = await invoke("greet", {
|
||||||
|
name: greetInputEl.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
greetInputEl = document.querySelector("#greet-input");
|
||||||
|
greetMsgEl = document.querySelector("#greet-msg");
|
||||||
|
document.querySelector("#greet-form")?.addEventListener("submit", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
greet();
|
||||||
|
});
|
||||||
|
});
|
1
package.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ "dependencies": { "lucide-react": "^0.460.0", "react-dom": "^18.3.1" } }
|
BIN
scribe/bun.lockb
@ -1,44 +0,0 @@
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
|
||||||
|
|
||||||
import {EditorState} from "prosemirror-state"
|
|
||||||
import {EditorView} from "prosemirror-view"
|
|
||||||
import {Schema, DOMParser} from "prosemirror-model"
|
|
||||||
import {schema} from "prosemirror-schema-basic"
|
|
||||||
import {addListNodes} from "prosemirror-schema-list"
|
|
||||||
import {exampleSetup} from "prosemirror-example-setup"
|
|
||||||
|
|
||||||
// Mix the nodes from prosemirror-schema-list into the basic schema to
|
|
||||||
// create a schema with list support.
|
|
||||||
const mySchema = new Schema({
|
|
||||||
nodes: addListNodes(schema.spec.nodes, "paragraph block*", "block"),
|
|
||||||
marks: schema.spec.marks
|
|
||||||
})
|
|
||||||
|
|
||||||
window.view = new EditorView(document.querySelector("#editor"), {
|
|
||||||
state: EditorState.create({
|
|
||||||
doc: DOMParser.fromSchema(mySchema).parse(document.querySelector("#content")),
|
|
||||||
plugins: exampleSetup({schema: mySchema})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
let greetInputEl: HTMLInputElement | null;
|
|
||||||
let greetMsgEl: HTMLElement | null;
|
|
||||||
|
|
||||||
async function greet() {
|
|
||||||
if (greetMsgEl && greetInputEl) {
|
|
||||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
|
||||||
greetMsgEl.textContent = await invoke("greet", {
|
|
||||||
name: greetInputEl.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", () => {
|
|
||||||
greetInputEl = document.querySelector("#greet-input");
|
|
||||||
greetMsgEl = document.querySelector("#greet-msg");
|
|
||||||
document.querySelector("#greet-form")?.addEventListener("submit", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
greet();
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,21 +0,0 @@
|
|||||||
import {EditorState} from "prosemirror-state"
|
|
||||||
import {EditorView} from "prosemirror-view"
|
|
||||||
import {Schema, DOMParser} from "prosemirror-model"
|
|
||||||
import {schema} from "prosemirror-schema-basic"
|
|
||||||
import {addListNodes} from "prosemirror-schema-list"
|
|
||||||
import {exampleSetup} from "prosemirror-example-setup"
|
|
||||||
|
|
||||||
// Mix the nodes from prosemirror-schema-list into the basic schema to
|
|
||||||
// create a schema with list support.
|
|
||||||
const mySchema = new Schema({
|
|
||||||
nodes: addListNodes(schema.spec.nodes, "paragraph block*", "block"),
|
|
||||||
marks: schema.spec.marks
|
|
||||||
})
|
|
||||||
|
|
||||||
window.view = new EditorView(document.querySelector("#editor"), {
|
|
||||||
state: EditorState.create({
|
|
||||||
doc: DOMParser.fromSchema(mySchema).parse(document.querySelector("#content")),
|
|
||||||
plugins: exampleSetup({schema: mySchema})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|