From ae5aeeef6d5ce941a99a84419f6c269d8ba3ef09 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Thu, 11 Sep 2025 10:50:52 -0700 Subject: [PATCH 1/4] frontend first --- .../src/components/editor-area/index.tsx | 17 +++++++++++++++++ packages/tiptap/src/editor/index.tsx | 2 ++ 2 files changed, 19 insertions(+) diff --git a/apps/desktop/src/components/editor-area/index.tsx b/apps/desktop/src/components/editor-area/index.tsx index e6a789bd3..a8367650f 100644 --- a/apps/desktop/src/components/editor-area/index.tsx +++ b/apps/desktop/src/components/editor-area/index.tsx @@ -253,6 +253,21 @@ export default function EditorArea({ setAnnotationBox(null); }; + const handleImagePaste = useCallback(async (file: File) => { + // TODO: Handle pasted image file + // - Upload the file to storage + // - Get back image URL + // - Insert into editor at cursor position + console.log('Image pasted:', file.name, file.size); + }, []); + + const handleImageCopy = useCallback(async (imageUrl: string) => { + // TODO: Handle copying image to clipboard + // - Fetch image as blob + // - Copy to clipboard + console.log('Image copy requested:', imageUrl); + }, []); + const isEnhancedNote = !showRaw && !!enhancedContent; return ( @@ -286,6 +301,8 @@ export default function EditorArea({ initialContent={noteContent} editable={enhance.status !== "pending"} setContentFromOutside={!showRaw && enhance.status === "pending"} + onImagePaste={handleImagePaste} + onImageCopy={handleImageCopy} mentionConfig={{ trigger: "@", handleSearch: handleMentionSearch, diff --git a/packages/tiptap/src/editor/index.tsx b/packages/tiptap/src/editor/index.tsx index 688226302..6aa76d019 100644 --- a/packages/tiptap/src/editor/index.tsx +++ b/packages/tiptap/src/editor/index.tsx @@ -15,6 +15,8 @@ interface EditorProps { editable?: boolean; setContentFromOutside?: boolean; mentionConfig: MentionConfig; + onImagePaste?: (file: File) => void; + onImageCopy?: (imageUrl: string) => void; } const Editor = forwardRef<{ editor: TiptapEditor | null }, EditorProps>( From 55beeda03908aeec7b27391ec625dce92d905382 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Thu, 18 Sep 2025 09:23:09 +0900 Subject: [PATCH 2/4] wip --- Cargo.lock | 1 + .../src/components/editor-area/index.tsx | 3 +- packages/tiptap/package.json | 2 + packages/tiptap/src/editor/index.tsx | 7 +- packages/tiptap/src/shared/extensions.ts | 79 ++++++++++++++++++- plugins/misc/Cargo.toml | 1 + plugins/misc/build.rs | 2 + plugins/misc/js/bindings.gen.ts | 6 ++ .../autogenerated/commands/image_delete.toml | 13 +++ .../autogenerated/commands/image_upload.toml | 13 +++ .../permissions/autogenerated/reference.md | 54 +++++++++++++ plugins/misc/permissions/default.toml | 2 + plugins/misc/permissions/schemas/schema.json | 28 ++++++- plugins/misc/src/commands.rs | 45 +++++++++++ plugins/misc/src/lib.rs | 2 + pnpm-lock.yaml | 78 +++++++++++++++--- 16 files changed, 315 insertions(+), 21 deletions(-) create mode 100644 plugins/misc/permissions/autogenerated/commands/image_delete.toml create mode 100644 plugins/misc/permissions/autogenerated/commands/image_upload.toml diff --git a/Cargo.lock b/Cargo.lock index f4219f402..c050f0b86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14598,6 +14598,7 @@ dependencies = [ "tauri-plugin", "tauri-plugin-opener", "tauri-specta", + "uuid", "vergen-gix", ] diff --git a/apps/desktop/src/components/editor-area/index.tsx b/apps/desktop/src/components/editor-area/index.tsx index a8367650f..1dd68e452 100644 --- a/apps/desktop/src/components/editor-area/index.tsx +++ b/apps/desktop/src/components/editor-area/index.tsx @@ -301,12 +301,11 @@ export default function EditorArea({ initialContent={noteContent} editable={enhance.status !== "pending"} setContentFromOutside={!showRaw && enhance.status === "pending"} - onImagePaste={handleImagePaste} - onImageCopy={handleImageCopy} mentionConfig={{ trigger: "@", handleSearch: handleMentionSearch, }} + sessionId={sessionId} /> ) : } diff --git a/packages/tiptap/package.json b/packages/tiptap/package.json index 952539a0e..f221d71a4 100644 --- a/packages/tiptap/package.json +++ b/packages/tiptap/package.json @@ -16,6 +16,7 @@ "dependencies": { "@floating-ui/dom": "^1.7.4", "@hypr/plugin-db": "workspace:^", + "@hypr/plugin-misc": "workspace:^", "@hypr/ui": "workspace:^", "@hypr/utils": "workspace:^", "@remixicon/react": "^4.6.0", @@ -24,6 +25,7 @@ "@tiptap/core": "^3.4.1", "@tiptap/extension-bubble-menu": "^3.4.1", "@tiptap/extension-document": "^3.4.1", + "@tiptap/extension-file-handler": "^3.4.2", "@tiptap/extension-highlight": "^3.4.1", "@tiptap/extension-history": "^3.4.1", "@tiptap/extension-image": "^3.4.1", diff --git a/packages/tiptap/src/editor/index.tsx b/packages/tiptap/src/editor/index.tsx index 6aa76d019..d05d4bd08 100644 --- a/packages/tiptap/src/editor/index.tsx +++ b/packages/tiptap/src/editor/index.tsx @@ -15,12 +15,11 @@ interface EditorProps { editable?: boolean; setContentFromOutside?: boolean; mentionConfig: MentionConfig; - onImagePaste?: (file: File) => void; - onImageCopy?: (imageUrl: string) => void; + sessionId?: string; } const Editor = forwardRef<{ editor: TiptapEditor | null }, EditorProps>( - ({ handleChange, initialContent, editable = true, setContentFromOutside = false, mentionConfig }, ref) => { + ({ handleChange, initialContent, editable = true, setContentFromOutside = false, mentionConfig, sessionId }, ref) => { const previousContentRef = useRef(initialContent); const onUpdate = ({ editor }: { editor: TiptapEditor }) => { @@ -33,7 +32,7 @@ const Editor = forwardRef<{ editor: TiptapEditor | null }, EditorProps>( const editor = useEditor({ extensions: [ - ...shared.extensions, + ...(sessionId ? shared.createExtensions(sessionId) : shared.extensions), mention(mentionConfig), ], editable, diff --git a/packages/tiptap/src/shared/extensions.ts b/packages/tiptap/src/shared/extensions.ts index 54fbc2f5e..a53f6bf33 100644 --- a/packages/tiptap/src/shared/extensions.ts +++ b/packages/tiptap/src/shared/extensions.ts @@ -6,6 +6,9 @@ import TaskItem from "@tiptap/extension-task-item"; import TaskList from "@tiptap/extension-task-list"; import Underline from "@tiptap/extension-underline"; import StarterKit from "@tiptap/starter-kit"; +import FileHandler from "@tiptap/extension-file-handler"; + +import { commands as miscCommands } from "@hypr/plugin-misc"; import { AIHighlight } from "./ai-highlight"; import { StreamingAnimation } from "./animation"; @@ -13,7 +16,13 @@ import { ClipboardTextSerializer } from "./clipboard"; import CustomListKeymap from "./custom-list-keymap"; import { Hashtag } from "./hashtag"; -export const extensions = [ +// Helper function to extract file extension +const getFileExtension = (filename: string): string => { + const ext = filename.split('.').pop()?.toLowerCase(); + return ext || 'png'; +}; + +export const createExtensions = (sessionId: string) => [ StarterKit.configure({ heading: { levels: [1], @@ -89,4 +98,72 @@ export const extensions = [ CustomListKeymap, StreamingAnimation, ClipboardTextSerializer, + FileHandler.configure({ + allowedMimeTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'], + onDrop: async (currentEditor, files, pos) => { + console.log("onDrop", files, pos) + for (const file of files) { + try { + // Convert file to bytes + const arrayBuffer = await file.arrayBuffer() + const bytes = new Uint8Array(arrayBuffer) + const extension = getFileExtension(file.name) + + // Upload via Tauri command + const imageUrl = await miscCommands.imageUpload(sessionId, Array.from(bytes), extension) + + // Insert URL (not base64!) + currentEditor + .chain() + .insertContentAt(pos, { + type: 'image', + attrs: { + src: imageUrl, + }, + }) + .focus() + .run() + } catch (error) { + console.error('Failed to upload image:', error) + } + } + }, + onPaste: async (currentEditor, files, htmlContent) => { + for (const file of files) { + console.log("onPaste", files, htmlContent) + if (htmlContent) { + // if there is htmlContent, stop manual insertion & let other extensions handle insertion via inputRule + console.log(htmlContent) // eslint-disable-line no-console + return false + } + + try { + // Convert file to bytes + const arrayBuffer = await file.arrayBuffer() + const bytes = new Uint8Array(arrayBuffer) + const extension = getFileExtension(file.name) + + // Upload via Tauri command + const imageUrl = await miscCommands.imageUpload(sessionId, Array.from(bytes), extension) + + // Insert URL (not base64!) + currentEditor + .chain() + .insertContentAt(currentEditor.state.selection.anchor, { + type: 'image', + attrs: { + src: imageUrl, + }, + }) + .focus() + .run() + } catch (error) { + console.error('Failed to upload image:', error) + } + } + }, + }), ]; + +// For backward compatibility - default extensions without session ID +export const extensions = createExtensions(''); diff --git a/plugins/misc/Cargo.toml b/plugins/misc/Cargo.toml index 8af791a54..c5b9f8be1 100644 --- a/plugins/misc/Cargo.toml +++ b/plugins/misc/Cargo.toml @@ -27,3 +27,4 @@ lazy_static = { workspace = true } regex = { workspace = true } specta = { workspace = true } sysinfo = { workspace = true } +uuid = { version = "1.0", features = ["v4"] } diff --git a/plugins/misc/build.rs b/plugins/misc/build.rs index 4f18bd80d..11f40a756 100644 --- a/plugins/misc/build.rs +++ b/plugins/misc/build.rs @@ -7,6 +7,8 @@ const COMMANDS: &[&str] = &[ "audio_open", "audio_exist", "audio_delete", + "image_upload", + "image_delete", ]; fn main() { diff --git a/plugins/misc/js/bindings.gen.ts b/plugins/misc/js/bindings.gen.ts index 6b4449ac1..eba784969 100644 --- a/plugins/misc/js/bindings.gen.ts +++ b/plugins/misc/js/bindings.gen.ts @@ -30,6 +30,12 @@ async audioOpen(sessionId: string) : Promise { }, async audioDelete(sessionId: string) : Promise { return await TAURI_INVOKE("plugin:misc|audio_delete", { sessionId }); +}, +async imageUpload(sessionId: string, imageData: number[], extension: string) : Promise { + return await TAURI_INVOKE("plugin:misc|image_upload", { sessionId, imageData, extension }); +}, +async imageDelete(sessionId: string, imageFilename: string) : Promise { + return await TAURI_INVOKE("plugin:misc|image_delete", { sessionId, imageFilename }); } } diff --git a/plugins/misc/permissions/autogenerated/commands/image_delete.toml b/plugins/misc/permissions/autogenerated/commands/image_delete.toml new file mode 100644 index 000000000..72eb41937 --- /dev/null +++ b/plugins/misc/permissions/autogenerated/commands/image_delete.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-image-delete" +description = "Enables the image_delete command without any pre-configured scope." +commands.allow = ["image_delete"] + +[[permission]] +identifier = "deny-image-delete" +description = "Denies the image_delete command without any pre-configured scope." +commands.deny = ["image_delete"] diff --git a/plugins/misc/permissions/autogenerated/commands/image_upload.toml b/plugins/misc/permissions/autogenerated/commands/image_upload.toml new file mode 100644 index 000000000..ad7724289 --- /dev/null +++ b/plugins/misc/permissions/autogenerated/commands/image_upload.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-image-upload" +description = "Enables the image_upload command without any pre-configured scope." +commands.allow = ["image_upload"] + +[[permission]] +identifier = "deny-image-upload" +description = "Denies the image_upload command without any pre-configured scope." +commands.deny = ["image_upload"] diff --git a/plugins/misc/permissions/autogenerated/reference.md b/plugins/misc/permissions/autogenerated/reference.md index 3a82d84bd..d6e514a1b 100644 --- a/plugins/misc/permissions/autogenerated/reference.md +++ b/plugins/misc/permissions/autogenerated/reference.md @@ -12,6 +12,8 @@ Default permissions for the plugin - `allow-audio-open` - `allow-audio-exist` - `allow-audio-delete` +- `allow-image-upload` +- `allow-image-delete` ## Permission Table @@ -181,6 +183,58 @@ Denies the get_git_hash command without any pre-configured scope. +`misc:allow-image-delete` + + + + +Enables the image_delete command without any pre-configured scope. + + + + + + + +`misc:deny-image-delete` + + + + +Denies the image_delete command without any pre-configured scope. + + + + + + + +`misc:allow-image-upload` + + + + +Enables the image_upload command without any pre-configured scope. + + + + + + + +`misc:deny-image-upload` + + + + +Denies the image_upload command without any pre-configured scope. + + + + + + + `misc:allow-opinionated-md-to-html` diff --git a/plugins/misc/permissions/default.toml b/plugins/misc/permissions/default.toml index e3072d21a..66da0a90b 100644 --- a/plugins/misc/permissions/default.toml +++ b/plugins/misc/permissions/default.toml @@ -9,4 +9,6 @@ permissions = [ "allow-audio-open", "allow-audio-exist", "allow-audio-delete", + "allow-image-upload", + "allow-image-delete", ] diff --git a/plugins/misc/permissions/schemas/schema.json b/plugins/misc/permissions/schemas/schema.json index 624ba5654..88ebfec97 100644 --- a/plugins/misc/permissions/schemas/schema.json +++ b/plugins/misc/permissions/schemas/schema.json @@ -366,6 +366,30 @@ "const": "deny-get-git-hash", "markdownDescription": "Denies the get_git_hash command without any pre-configured scope." }, + { + "description": "Enables the image_delete command without any pre-configured scope.", + "type": "string", + "const": "allow-image-delete", + "markdownDescription": "Enables the image_delete command without any pre-configured scope." + }, + { + "description": "Denies the image_delete command without any pre-configured scope.", + "type": "string", + "const": "deny-image-delete", + "markdownDescription": "Denies the image_delete command without any pre-configured scope." + }, + { + "description": "Enables the image_upload command without any pre-configured scope.", + "type": "string", + "const": "allow-image-upload", + "markdownDescription": "Enables the image_upload command without any pre-configured scope." + }, + { + "description": "Denies the image_upload command without any pre-configured scope.", + "type": "string", + "const": "deny-image-upload", + "markdownDescription": "Denies the image_upload command without any pre-configured scope." + }, { "description": "Enables the opinionated_md_to_html command without any pre-configured scope.", "type": "string", @@ -391,10 +415,10 @@ "markdownDescription": "Denies the parse_meeting_link command without any pre-configured scope." }, { - "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-git-hash`\n- `allow-get-fingerprint`\n- `allow-opinionated-md-to-html`\n- `allow-delete-session-folder`\n- `allow-parse-meeting-link`\n- `allow-audio-open`\n- `allow-audio-exist`\n- `allow-audio-delete`", + "description": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-git-hash`\n- `allow-get-fingerprint`\n- `allow-opinionated-md-to-html`\n- `allow-delete-session-folder`\n- `allow-parse-meeting-link`\n- `allow-audio-open`\n- `allow-audio-exist`\n- `allow-audio-delete`\n- `allow-image-upload`\n- `allow-image-delete`", "type": "string", "const": "default", - "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-git-hash`\n- `allow-get-fingerprint`\n- `allow-opinionated-md-to-html`\n- `allow-delete-session-folder`\n- `allow-parse-meeting-link`\n- `allow-audio-open`\n- `allow-audio-exist`\n- `allow-audio-delete`" + "markdownDescription": "Default permissions for the plugin\n#### This default permission set includes:\n\n- `allow-get-git-hash`\n- `allow-get-fingerprint`\n- `allow-opinionated-md-to-html`\n- `allow-delete-session-folder`\n- `allow-parse-meeting-link`\n- `allow-audio-open`\n- `allow-audio-exist`\n- `allow-audio-delete`\n- `allow-image-upload`\n- `allow-image-delete`" } ] } diff --git a/plugins/misc/src/commands.rs b/plugins/misc/src/commands.rs index 3ae8ce4e2..ba1f77acf 100644 --- a/plugins/misc/src/commands.rs +++ b/plugins/misc/src/commands.rs @@ -92,3 +92,48 @@ pub async fn parse_meeting_link( ) -> Option { app.parse_meeting_link(&text) } + +#[tauri::command] +#[specta::specta] +pub async fn image_upload( + app: tauri::AppHandle, + session_id: String, + image_data: Vec, + extension: String, +) -> Result { + let data_dir = app.path().app_data_dir().unwrap(); + let session_dir = data_dir.join(&session_id); + let images_dir = session_dir.join("images"); + + // Create directories if they don't exist + std::fs::create_dir_all(&images_dir).map_err(|e| e.to_string())?; + + // Generate unique filename + let uuid = uuid::Uuid::new_v4(); + let filename = format!("{}.{}", uuid, extension); + let file_path = images_dir.join(&filename); + + // Write image data to file + std::fs::write(&file_path, image_data).map_err(|e| e.to_string())?; + + // Return tauri local URL + let url = format!("tauri://localhost/{}/images/{}", session_id, filename); + Ok(url) +} + +#[tauri::command] +#[specta::specta] +pub async fn image_delete( + app: tauri::AppHandle, + session_id: String, + image_filename: String, +) -> Result<(), String> { + let data_dir = app.path().app_data_dir().unwrap(); + let image_path = data_dir.join(session_id).join("images").join(image_filename); + + if image_path.exists() { + std::fs::remove_file(image_path).map_err(|e| e.to_string())?; + } + + Ok(()) +} diff --git a/plugins/misc/src/lib.rs b/plugins/misc/src/lib.rs index 0bc337896..bbcd7b00c 100644 --- a/plugins/misc/src/lib.rs +++ b/plugins/misc/src/lib.rs @@ -16,6 +16,8 @@ fn make_specta_builder() -> tauri_specta::Builder { commands::audio_exist::, commands::audio_open::, commands::audio_delete::, + commands::image_upload::, + commands::image_delete::, ]) .error_handling(tauri_specta::ErrorHandlingMode::Throw) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b267490e4..a0a3d6e45 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -603,13 +603,13 @@ importers: version: link:../utils '@remixicon/react': specifier: ^4.6.0 - version: 4.6.0(react@18.3.1) + version: 4.6.0(react@19.1.1) '@tanstack/react-query': specifier: ^5.87.1 - version: 5.87.1(react@18.3.1) + version: 5.87.1(react@19.1.1) '@tanstack/react-router': specifier: ^1.131.35 - version: 1.131.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.131.35(react-dom@18.3.1(react@19.1.1))(react@19.1.1) '@tiptap/core': specifier: ^3.4.1 version: 3.4.1(@tiptap/pm@3.4.1) @@ -619,6 +619,9 @@ importers: '@tiptap/extension-document': specifier: ^3.4.1 version: 3.4.1(@tiptap/core@3.4.1(@tiptap/pm@3.4.1)) + '@tiptap/extension-file-handler': + specifier: ^3.4.2 + version: 3.4.2(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/extension-text-style@3.4.2(@tiptap/core@3.4.1(@tiptap/pm@3.4.1)))(@tiptap/pm@3.4.1) '@tiptap/extension-highlight': specifier: ^3.4.1 version: 3.4.1(@tiptap/core@3.4.1(@tiptap/pm@3.4.1)) @@ -663,7 +666,7 @@ importers: version: 3.4.1 '@tiptap/react': specifier: ^3.4.1 - version: 3.4.1(@floating-ui/dom@1.7.4)(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.4.1(@floating-ui/dom@1.7.4)(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@19.1.1))(react@19.1.1) '@tiptap/starter-kit': specifier: ^3.4.1 version: 3.4.1 @@ -675,7 +678,7 @@ importers: version: 2.1.1 lucide-react: specifier: ^0.525.0 - version: 0.525.0(react@18.3.1) + version: 0.525.0(react@19.1.1) prosemirror-commands: specifier: ^1.7.1 version: 1.7.1 @@ -687,10 +690,10 @@ importers: version: 1.4.3 react: specifier: ^18.3.1 - version: 18.3.1 + version: 19.1.1 react-dom: specifier: ^18.3.1 - version: 18.3.1(react@18.3.1) + version: 18.3.1(react@19.1.1) turndown: specifier: ^7.2.1 version: 7.2.1 @@ -4207,6 +4210,13 @@ packages: peerDependencies: '@tiptap/extensions': ^3.4.1 + '@tiptap/extension-file-handler@3.4.2': + resolution: {integrity: sha512-MjX1Y58/pGg7pbsZrg3iIBQy0HDDa/meNdna+tUyQIx0wJoQax1bmuCUug2QFer9bEZ/BYLa+SoqxILvNz1Ojg==} + peerDependencies: + '@tiptap/core': ^3.4.2 + '@tiptap/extension-text-style': ^3.4.2 + '@tiptap/pm': ^3.4.2 + '@tiptap/extension-floating-menu@3.4.1': resolution: {integrity: sha512-9qGINja20Kz4XI0uESoYiwgGo+ejvDrHiSoRmd3jkDMv6fGMXj1U+HYzqhXZTV30kuQZQN8twNmbmzBu+jltYQ==} peerDependencies: @@ -4314,6 +4324,11 @@ packages: peerDependencies: '@tiptap/extension-list': ^3.4.1 + '@tiptap/extension-text-style@3.4.2': + resolution: {integrity: sha512-ioCf7VxWj2t+seC2vfzGtGlcToGKpwz6R5HMpo6/CSBDTZc5LsPTiJqJ6R6ahjqWwAKHI6SzlW5vtS36OywDzw==} + peerDependencies: + '@tiptap/core': ^3.4.2 + '@tiptap/extension-text@3.4.1': resolution: {integrity: sha512-6qcBjRAE4HpjbFShf9e44uBuq8jMvrumzvK4FwhAwZ7S8nyywN1WLZY3S1UQLMYJr3wZn+9IhKMb2CjBeGIPiA==} peerDependencies: @@ -14011,6 +14026,10 @@ snapshots: dependencies: react: 18.3.1 + '@remixicon/react@4.6.0(react@19.1.1)': + dependencies: + react: 19.1.1 + '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/plugin-alias@5.1.1(rollup@4.50.0)': @@ -14471,6 +14490,17 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 + '@tanstack/react-router@1.131.35(react-dom@18.3.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@tanstack/history': 1.131.2 + '@tanstack/react-store': 0.7.4(react-dom@18.3.1(react@19.1.1))(react@19.1.1) + '@tanstack/router-core': 1.131.35 + isbot: 5.1.30 + react: 19.1.1 + react-dom: 18.3.1(react@19.1.1) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + '@tanstack/react-start-client@1.131.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/react-router': 1.131.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -14585,6 +14615,13 @@ snapshots: react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.5.0(react@18.3.1) + '@tanstack/react-store@0.7.4(react-dom@18.3.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@tanstack/store': 0.7.4 + react: 19.1.1 + react-dom: 18.3.1(react@19.1.1) + use-sync-external-store: 1.5.0(react@19.1.1) + '@tanstack/router-core@1.131.35': dependencies: '@tanstack/history': 1.131.2 @@ -14935,6 +14972,12 @@ snapshots: dependencies: '@tiptap/extensions': 3.4.1(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1) + '@tiptap/extension-file-handler@3.4.2(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/extension-text-style@3.4.2(@tiptap/core@3.4.1(@tiptap/pm@3.4.1)))(@tiptap/pm@3.4.1)': + dependencies: + '@tiptap/core': 3.4.1(@tiptap/pm@3.4.1) + '@tiptap/extension-text-style': 3.4.2(@tiptap/core@3.4.1(@tiptap/pm@3.4.1)) + '@tiptap/pm': 3.4.1 + '@tiptap/extension-floating-menu@3.4.1(@floating-ui/dom@1.7.4)(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1)': dependencies: '@floating-ui/dom': 1.7.4 @@ -15024,6 +15067,10 @@ snapshots: dependencies: '@tiptap/extension-list': 3.4.1(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1) + '@tiptap/extension-text-style@3.4.2(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))': + dependencies: + '@tiptap/core': 3.4.1(@tiptap/pm@3.4.1) + '@tiptap/extension-text@3.4.1(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))': dependencies: '@tiptap/core': 3.4.1(@tiptap/pm@3.4.1) @@ -15062,7 +15109,7 @@ snapshots: prosemirror-transform: 1.10.4 prosemirror-view: 1.41.0 - '@tiptap/react@3.4.1(@floating-ui/dom@1.7.4)(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@tiptap/react@3.4.1(@floating-ui/dom@1.7.4)(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1)(@types/react-dom@18.3.7(@types/react@18.3.24))(@types/react@18.3.24)(react-dom@18.3.1(react@19.1.1))(react@19.1.1)': dependencies: '@tiptap/core': 3.4.1(@tiptap/pm@3.4.1) '@tiptap/pm': 3.4.1 @@ -15070,9 +15117,9 @@ snapshots: '@types/react-dom': 18.3.7(@types/react@18.3.24) '@types/use-sync-external-store': 0.0.6 fast-deep-equal: 3.1.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - use-sync-external-store: 1.5.0(react@18.3.1) + react: 19.1.1 + react-dom: 18.3.1(react@19.1.1) + use-sync-external-store: 1.5.0(react@19.1.1) optionalDependencies: '@tiptap/extension-bubble-menu': 3.4.1(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1) '@tiptap/extension-floating-menu': 3.4.1(@floating-ui/dom@1.7.4)(@tiptap/core@3.4.1(@tiptap/pm@3.4.1))(@tiptap/pm@3.4.1) @@ -19400,6 +19447,10 @@ snapshots: dependencies: react: 18.3.1 + lucide-react@0.525.0(react@19.1.1): + dependencies: + react: 19.1.1 + luxon@3.7.1: optional: true @@ -21442,7 +21493,6 @@ snapshots: loose-envify: 1.4.0 react: 19.1.1 scheduler: 0.23.2 - optional: true react-draggable@4.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -23212,6 +23262,10 @@ snapshots: dependencies: react: 18.3.1 + use-sync-external-store@1.5.0(react@19.1.1): + dependencies: + react: 19.1.1 + userhome@1.0.1: {} util-deprecate@1.0.2: {} From 1f0d6bece451b79914567cf5c499075985450792 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Sat, 20 Sep 2025 14:00:22 +0900 Subject: [PATCH 3/4] wip --- packages/tiptap/src/shared/extensions.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/tiptap/src/shared/extensions.ts b/packages/tiptap/src/shared/extensions.ts index a53f6bf33..13ac937d9 100644 --- a/packages/tiptap/src/shared/extensions.ts +++ b/packages/tiptap/src/shared/extensions.ts @@ -111,6 +111,7 @@ export const createExtensions = (sessionId: string) => [ // Upload via Tauri command const imageUrl = await miscCommands.imageUpload(sessionId, Array.from(bytes), extension) + console.log("full note html: ", currentEditor.getHTML()) // Insert URL (not base64!) currentEditor @@ -145,6 +146,7 @@ export const createExtensions = (sessionId: string) => [ // Upload via Tauri command const imageUrl = await miscCommands.imageUpload(sessionId, Array.from(bytes), extension) + console.log("full note html: ", currentEditor.getHTML()) // Insert URL (not base64!) currentEditor From 10dd6d1584dc7c28e2ee6e5ba505002cf3040275 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Sat, 20 Sep 2025 14:00:45 +0900 Subject: [PATCH 4/4] wip --- Cargo.lock | 1 + plugins/listener/Cargo.toml | 1 + plugins/misc/src/commands.rs | 4 ++-- pnpm-lock.yaml | 3 +++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e34a755b..154b81dcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14435,6 +14435,7 @@ dependencies = [ name = "tauri-plugin-listener" version = "0.1.0" dependencies = [ + "aec", "agc", "audio", "audio-utils", diff --git a/plugins/listener/Cargo.toml b/plugins/listener/Cargo.toml index 399cb48ba..0b619932c 100644 --- a/plugins/listener/Cargo.toml +++ b/plugins/listener/Cargo.toml @@ -18,6 +18,7 @@ specta-typescript = { workspace = true } uuid = { workspace = true } [dependencies] +hypr-aec = { workspace = true } hypr-agc = { workspace = true } hypr-audio = { workspace = true } hypr-audio-utils = { workspace = true } diff --git a/plugins/misc/src/commands.rs b/plugins/misc/src/commands.rs index a931688b7..c98755f2d 100644 --- a/plugins/misc/src/commands.rs +++ b/plugins/misc/src/commands.rs @@ -107,7 +107,7 @@ pub async fn image_upload( image_data: Vec, extension: String, ) -> Result { - let data_dir = app.path().app_data_dir().unwrap(); + let data_dir = app.path().app_data_dir().map_err(|e| e.to_string())?; let session_dir = data_dir.join(&session_id); let images_dir = session_dir.join("images"); @@ -134,7 +134,7 @@ pub async fn image_delete( session_id: String, image_filename: String, ) -> Result<(), String> { - let data_dir = app.path().app_data_dir().unwrap(); + let data_dir = app.path().app_data_dir().map_err(|e| e.to_string())?; let image_path = data_dir.join(session_id).join("images").join(image_filename); if image_path.exists() { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0a3d6e45..e1c59a5ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -595,6 +595,9 @@ importers: '@hypr/plugin-db': specifier: workspace:^ version: link:../../plugins/db + '@hypr/plugin-misc': + specifier: workspace:^ + version: link:../../plugins/misc '@hypr/ui': specifier: workspace:^ version: link:../ui