Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/components/ContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState, useEffect, useCallback, useRef, type ReactNode } from 'react'
import { NODE_PATHS } from '../lib/constants'

interface ContextMenuItem {
id: string
Expand Down Expand Up @@ -309,14 +310,14 @@ export function getCanvasContextMenuItems(options: {
id: 'add-node',
label: 'Add Node',
submenu: [
{ id: 'add-prompt', label: 'Prompt', onClick: () => options.onAddNode?.('input/prompt') },
{ id: 'add-image', label: 'Image Source', onClick: () => options.onAddNode?.('input/image') },
{ id: 'add-seed', label: 'Seed', onClick: () => options.onAddNode?.('input/seed') },
{ id: 'add-prompt', label: 'Prompt', onClick: () => options.onAddNode?.(NODE_PATHS.PROMPT) },
{ id: 'add-image', label: 'Image Source', onClick: () => options.onAddNode?.(NODE_PATHS.IMAGE_SOURCE) },
{ id: 'add-seed', label: 'Seed', onClick: () => options.onAddNode?.(NODE_PATHS.SEED) },
{ id: 'sep', label: '', separator: true },
{ id: 'add-fal', label: 'Fal Flux', onClick: () => options.onAddNode?.('generation/fal-flux') },
{ id: 'add-gemini', label: 'Gemini', onClick: () => options.onAddNode?.('generation/gemini') },
{ id: 'add-fal', label: 'Fal Flux', onClick: () => options.onAddNode?.(NODE_PATHS.FAL_FLUX) },
{ id: 'add-gemini', label: 'Gemini', onClick: () => options.onAddNode?.(NODE_PATHS.GEMINI) },
{ id: 'sep2', label: '', separator: true },
{ id: 'add-output', label: 'Image Output', onClick: () => options.onAddNode?.('output/image') },
{ id: 'add-output', label: 'Image Output', onClick: () => options.onAddNode?.(NODE_PATHS.IMAGE_OUTPUT) },
],
},
]
Expand Down
3 changes: 2 additions & 1 deletion src/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component, type ReactNode, type ErrorInfo } from 'react'
import { STORAGE_KEYS } from '../lib/constants'

interface Props {
children: ReactNode
Expand Down Expand Up @@ -114,7 +115,7 @@ export class CanvasErrorBoundary extends ErrorBoundary {
<button
onClick={() => {
// Try to recover autosave
const autosave = localStorage.getItem('nanonodebanana_autosave')
const autosave = localStorage.getItem(STORAGE_KEYS.AUTOSAVE)
if (autosave) {
console.log('Autosave data found:', autosave)
alert('Autosave data found in console. Please copy it before reloading.')
Expand Down
7 changes: 4 additions & 3 deletions src/components/ImageHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState, useCallback, useMemo } from 'react'
import { useImageHistory } from '../hooks/useImageHistory'
import type { HistoryImage } from '../context/ImageHistoryContext'
import { NODE_PATHS, DRAG_DATA_TYPES } from '../lib/constants'

const VISIBLE_COUNT = 5 // Number of images to show in collapsed fan view

Expand Down Expand Up @@ -28,9 +29,9 @@ export function ImageHistory({ onImageDragStart }: ImageHistoryProps) {
// Handle drag start for image
const handleDragStart = useCallback(
(e: React.DragEvent, image: HistoryImage) => {
e.dataTransfer.setData('node-type', 'input/image')
e.dataTransfer.setData('image-url', image.imageUrl)
e.dataTransfer.setData('image-history-id', image.id)
e.dataTransfer.setData(DRAG_DATA_TYPES.NODE_TYPE, NODE_PATHS.IMAGE_SOURCE)
e.dataTransfer.setData(DRAG_DATA_TYPES.IMAGE_URL, image.imageUrl)
e.dataTransfer.setData(DRAG_DATA_TYPES.IMAGE_HISTORY_ID, image.id)
e.dataTransfer.effectAllowed = 'copy'
onImageDragStart?.(image)
},
Expand Down
12 changes: 6 additions & 6 deletions src/components/SettingsDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState, useEffect, useCallback } from 'react'
import { STORAGE_KEYS } from '../lib/constants'

interface SettingsDialogProps {
isOpen: boolean
Expand Down Expand Up @@ -29,7 +30,6 @@ const DEFAULT_SETTINGS: Settings = {
gridSize: 10,
}

const STORAGE_KEY = 'nanonodebanana_settings'

/**
* Settings dialog for configuring the workflow editor.
Expand All @@ -42,7 +42,7 @@ export function SettingsDialog({ isOpen, onClose }: SettingsDialogProps) {

// Load settings on mount
useEffect(() => {
const stored = localStorage.getItem(STORAGE_KEY)
const stored = localStorage.getItem(STORAGE_KEYS.SETTINGS)
if (stored) {
try {
const parsed = JSON.parse(stored)
Expand All @@ -55,7 +55,7 @@ export function SettingsDialog({ isOpen, onClose }: SettingsDialogProps) {

// Handle save
const handleSave = useCallback(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(settings))
localStorage.setItem(STORAGE_KEYS.SETTINGS, JSON.stringify(settings))
setSaved(true)
setTimeout(() => setSaved(false), 2000)
}, [settings])
Expand All @@ -64,7 +64,7 @@ export function SettingsDialog({ isOpen, onClose }: SettingsDialogProps) {
const handleReset = useCallback(() => {
if (confirm('Reset all settings to defaults?')) {
setSettings(DEFAULT_SETTINGS)
localStorage.removeItem(STORAGE_KEY)
localStorage.removeItem(STORAGE_KEYS.SETTINGS)
}
}, [])

Expand Down Expand Up @@ -336,7 +336,7 @@ export function useSettings(): Settings {
const [settings, setSettings] = useState<Settings>(DEFAULT_SETTINGS)

useEffect(() => {
const stored = localStorage.getItem(STORAGE_KEY)
const stored = localStorage.getItem(STORAGE_KEYS.SETTINGS)
if (stored) {
try {
const parsed = JSON.parse(stored)
Expand All @@ -348,7 +348,7 @@ export function useSettings(): Settings {

// Listen for storage changes
const handleStorage = (e: StorageEvent) => {
if (e.key === STORAGE_KEY && e.newValue) {
if (e.key === STORAGE_KEYS.SETTINGS && e.newValue) {
try {
const parsed = JSON.parse(e.newValue)
setSettings({ ...DEFAULT_SETTINGS, ...parsed })
Expand Down
7 changes: 3 additions & 4 deletions src/components/WorkflowCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { useClipboard } from '../hooks/useClipboard'
import { registerAllNodes } from '../nodes'
import { loadAutosave, enableAutosave, serialiseGraph } from '../lib/workflow-storage'
import { Minimap } from './Minimap'

const AUTOSAVE_KEY = 'nanonodebanana_autosave'
import { NODE_PATHS, STORAGE_KEYS } from '../lib/constants'

interface WorkflowCanvasProps {
onCanvasReady?: (canvas: LGraphCanvas) => void
Expand Down Expand Up @@ -219,7 +218,7 @@ export function WorkflowCanvas({ onCanvasReady }: WorkflowCanvasProps) {
graph: serialiseGraph(graph),
savedAt: new Date().toISOString(),
}
localStorage.setItem(AUTOSAVE_KEY, JSON.stringify(data))
localStorage.setItem(STORAGE_KEYS.AUTOSAVE, JSON.stringify(data))
}

initGraph()
Expand Down Expand Up @@ -304,7 +303,7 @@ export function WorkflowCanvas({ onCanvasReady }: WorkflowCanvasProps) {
const y = (event.clientY - rect.top - canvas.ds.offset[1]) / canvas.ds.scale

const LiteGraph = liteGraphRef.current
const node = LiteGraph.createNode('input/image')
const node = LiteGraph.createNode(NODE_PATHS.IMAGE_SOURCE)

if (node) {
node.pos = [x, y]
Expand Down
8 changes: 4 additions & 4 deletions src/context/ImageHistoryContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useEffect,
type ReactNode,
} from 'react'
import { STORAGE_KEYS } from '../lib/constants'

/**
* Represents a single image entry in the history.
Expand All @@ -30,7 +31,6 @@ interface ImageHistoryState {
maxImages: number
}

const STORAGE_KEY = 'nanonodebanana_image_history'
const MAX_IMAGES = 100

const ImageHistoryContext = createContext<ImageHistoryState | undefined>(undefined)
Expand All @@ -47,7 +47,7 @@ export function ImageHistoryProvider({ children }: ImageHistoryProviderProps) {
const [images, setImages] = useState<HistoryImage[]>(() => {
// Load from localStorage on initial render
try {
const stored = localStorage.getItem(STORAGE_KEY)
const stored = localStorage.getItem(STORAGE_KEYS.IMAGE_HISTORY)
if (stored) {
const parsed = JSON.parse(stored)
// Validate and return stored images
Expand All @@ -70,7 +70,7 @@ export function ImageHistoryProvider({ children }: ImageHistoryProviderProps) {
// Keep image URLs (they're usually blob: or short data URIs)
// For large base64, we'd need IndexedDB (future enhancement)
}))
localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore))
localStorage.setItem(STORAGE_KEYS.IMAGE_HISTORY, JSON.stringify(toStore))
} catch {
// localStorage quota exceeded - silently fail
// Future: migrate to IndexedDB for larger storage
Expand Down Expand Up @@ -100,7 +100,7 @@ export function ImageHistoryProvider({ children }: ImageHistoryProviderProps) {

const clearHistory = useCallback(() => {
setImages([])
localStorage.removeItem(STORAGE_KEY)
localStorage.removeItem(STORAGE_KEYS.IMAGE_HISTORY)
}, [])

const value: ImageHistoryState = {
Expand Down
7 changes: 4 additions & 3 deletions src/hooks/useClipboard.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect, useCallback, useRef } from 'react'
import type { LGraph, LGraphCanvas, LiteGraph as LiteGraphType } from 'litegraph.js'
import { NODE_PATHS } from '../lib/constants'

interface ClipboardOptions {
graph: LGraph | null
Expand Down Expand Up @@ -38,7 +39,7 @@ export function useClipboard({ graph, canvas, liteGraph, onNodeCreated }: Clipbo
const centerY = (canvas.canvas.height / 2 - canvas.ds.offset[1]) / canvas.ds.scale

// Create ImageSource node
const node = liteGraph.createNode('input/image')
const node = liteGraph.createNode(NODE_PATHS.IMAGE_SOURCE)
if (!node) return

node.pos = [centerX - 100, centerY - 75]
Expand Down Expand Up @@ -115,7 +116,7 @@ export function useClipboard({ graph, canvas, liteGraph, onNodeCreated }: Clipbo
const centerX = (canvas.canvas.width / 2 - canvas.ds.offset[0]) / canvas.ds.scale
const centerY = (canvas.canvas.height / 2 - canvas.ds.offset[1]) / canvas.ds.scale

const node = liteGraph.createNode('input/image')
const node = liteGraph.createNode(NODE_PATHS.IMAGE_SOURCE)
if (node) {
node.pos = [centerX - 100, centerY - 75]
node.properties = { ...node.properties, url: trimmed, source: 'url' }
Expand All @@ -131,7 +132,7 @@ export function useClipboard({ graph, canvas, liteGraph, onNodeCreated }: Clipbo
const centerX = (canvas.canvas.width / 2 - canvas.ds.offset[0]) / canvas.ds.scale
const centerY = (canvas.canvas.height / 2 - canvas.ds.offset[1]) / canvas.ds.scale

const node = liteGraph.createNode('input/prompt')
const node = liteGraph.createNode(NODE_PATHS.PROMPT)
if (node) {
node.pos = [centerX - 150, centerY - 60]
node.properties = { ...node.properties, text: trimmed }
Expand Down
Loading