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" />
|
||||
<link rel="stylesheet" href="/src/styles.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Tauri App</title>
|
||||
<script type="module" src="/src/main.ts" defer></script>
|
||||
<script type="module" src="/src/prosemirror.ts" defer></script>
|
||||
<title>Notes</title>
|
||||
<script type="module" src="/src/main.tsx" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -33,6 +32,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<p>Click on the Tauri logo to learn more about the framework</p>
|
||||
<div id="editor"></div>
|
||||
|
||||
<form class="row" id="greet-form">
|
||||
<input id="greet-input" placeholder="Enter a name..." />
|
||||
@ -41,7 +41,5 @@
|
||||
<p id="greet-msg"></p>
|
||||
</main>
|
||||
|
||||
<div id="editor"></div>
|
||||
<div id="content">test</div>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "scribe",
|
||||
"name": "notes",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
@ -10,13 +10,11 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@mui/material": "^6.1.7",
|
||||
"@tauri-apps/api": "^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"
|
||||
"@tauri-apps/plugin-shell": "^2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2",
|
611
scribe/src-tauri/Cargo.lock → notes/src-tauri/Cargo.lock
generated
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "scribe"
|
||||
name = "notes"
|
||||
version = "0.1.0"
|
||||
description = "A Tauri App"
|
||||
authors = ["you"]
|
||||
@ -11,7 +11,7 @@ edition = "2021"
|
||||
# The `_lib` suffix may seem redundant but it is necessary
|
||||
# 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
|
||||
name = "scribe_lib"
|
||||
name = "notes_lib"
|
||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||
|
||||
[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")]
|
||||
|
||||
fn main() {
|
||||
scribe_lib::run()
|
||||
notes_lib::run()
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "scribe",
|
||||
"productName": "notes",
|
||||
"version": "0.1.0",
|
||||
"identifier": "com.scribe.app",
|
||||
"identifier": "com.notes.app",
|
||||
"build": {
|
||||
"beforeDevCommand": "bun run dev",
|
||||
"devUrl": "http://localhost:1420",
|
||||
@ -13,7 +13,7 @@
|
||||
"withGlobalTauri": true,
|
||||
"windows": [
|
||||
{
|
||||
"title": "scribe",
|
||||
"title": "notes",
|
||||
"width": 800,
|
||||
"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})
|
||||
})
|
||||
})
|
||||
|