Switch IPFS from standalone kubo to rSpace collab-server endpoints
- Update IPFS_API_URL to ipfs-api.rspace.online (was kubo:5001) - Update IPFS_GATEWAY_URL to ipfs.rspace.online (was ipfs.jeffemmett.com) - Enhance image button: file upload via /api/uploads with IPFS encryption instead of manual URL prompt, with fallback on failure Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f71f9e6303
commit
b55362032d
|
|
@ -12,10 +12,10 @@ services:
|
|||
- INFISICAL_ENV=prod
|
||||
- INFISICAL_URL=http://infisical:8080
|
||||
- DATABASE_URL=postgresql://rnotes:${DB_PASSWORD}@rnotes-postgres:5432/rnotes
|
||||
# IPFS integration (encrypted file storage)
|
||||
# IPFS integration (encrypted file storage via rSpace collab-server kubo)
|
||||
- IPFS_ENABLED=true
|
||||
- IPFS_API_URL=http://kubo:5001
|
||||
- IPFS_GATEWAY_URL=https://ipfs.jeffemmett.com
|
||||
- IPFS_API_URL=https://ipfs-api.rspace.online
|
||||
- IPFS_GATEWAY_URL=https://ipfs.rspace.online
|
||||
volumes:
|
||||
- uploads_data:/app/uploads
|
||||
labels:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { useEditor, EditorContent } from '@tiptap/react';
|
||||
import StarterKit from '@tiptap/starter-kit';
|
||||
import Link from '@tiptap/extension-link';
|
||||
|
|
@ -45,6 +45,9 @@ function ToolbarButton({
|
|||
}
|
||||
|
||||
function RichEditor({ value, onChange, valueJson, placeholder: placeholderText }: Omit<NoteEditorProps, 'type'>) {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit.configure({
|
||||
|
|
@ -83,9 +86,33 @@ function RichEditor({ value, onChange, valueJson, placeholder: placeholderText }
|
|||
|
||||
const addImage = useCallback(() => {
|
||||
if (!editor) return;
|
||||
const url = window.prompt('Image URL');
|
||||
if (url) {
|
||||
editor.chain().focus().setImage({ src: url }).run();
|
||||
fileInputRef.current?.click();
|
||||
}, [editor]);
|
||||
|
||||
const handleFileUpload = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!editor || !e.target.files?.length) return;
|
||||
const file = e.target.files[0];
|
||||
e.target.value = ''; // reset input
|
||||
|
||||
setUploading(true);
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
const res = await fetch('/api/uploads', { method: 'POST', body: formData });
|
||||
if (!res.ok) throw new Error(`Upload failed: ${res.status}`);
|
||||
const data = await res.json();
|
||||
// Prefer IPFS proxy URL (decrypts on demand), fall back to local
|
||||
const src = data.ipfs
|
||||
? `/api/ipfs/${data.ipfs.cid}?key=${encodeURIComponent(data.ipfs.encKey)}`
|
||||
: data.url;
|
||||
editor.chain().focus().setImage({ src, alt: file.name }).run();
|
||||
} catch (err) {
|
||||
console.error('Image upload failed:', err);
|
||||
// Fall back to URL prompt
|
||||
const url = window.prompt('Upload failed. Enter image URL manually:');
|
||||
if (url) editor.chain().focus().setImage({ src: url }).run();
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
}, [editor]);
|
||||
|
||||
|
|
@ -200,10 +227,17 @@ function RichEditor({ value, onChange, valueJson, placeholder: placeholderText }
|
|||
</ToolbarButton>
|
||||
<ToolbarButton
|
||||
onClick={addImage}
|
||||
title="Add Image"
|
||||
title="Upload Image"
|
||||
>
|
||||
Img
|
||||
{uploading ? '...' : 'Img'}
|
||||
</ToolbarButton>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleFileUpload}
|
||||
className="hidden"
|
||||
/>
|
||||
|
||||
<div className="w-px h-5 bg-slate-700 mx-1" />
|
||||
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ export interface FileMetadata {
|
|||
|
||||
// ─── IPFS Client ───
|
||||
|
||||
const IPFS_API_URL = process.env.IPFS_API_URL || 'http://kubo:5001'
|
||||
const IPFS_GATEWAY_URL = process.env.IPFS_GATEWAY_URL || 'https://ipfs.jeffemmett.com'
|
||||
const IPFS_API_URL = process.env.IPFS_API_URL || 'https://ipfs-api.rspace.online'
|
||||
const IPFS_GATEWAY_URL = process.env.IPFS_GATEWAY_URL || 'https://ipfs.rspace.online'
|
||||
|
||||
export function isIPFSEnabled(): boolean {
|
||||
return process.env.IPFS_ENABLED === 'true'
|
||||
|
|
|
|||
Loading…
Reference in New Issue