+
0 ? step : (max - min) / 100}
+ value={Number.isFinite(value) ? clamp(value) : min}
+ onChange={(e) => {
+ const num = e.currentTarget.valueAsNumber
+ if (Number.isFinite(num)) { setText(String(num)); emit(num) }
+ }}
+ aria-label={label}
+ // nodrag: inside a React Flow node, dragging the thumb would move the node.
+ className="nodrag min-w-0 flex-1 accent-accent cursor-pointer"
+ />
+
{textInput}
+
+ )
+}
diff --git a/src/shared/components/ui/index.ts b/src/shared/components/ui/index.ts
index ef9d77f7..7c3a1147 100644
--- a/src/shared/components/ui/index.ts
+++ b/src/shared/components/ui/index.ts
@@ -4,3 +4,4 @@ export { ConfirmModal } from './ConfirmModal'
export { ColorPicker } from './ColorPicker'
export { PickerIcon } from './PickerIcon'
export { Toast } from './Toast'
+export { IntInput, FloatInput } from './NumberInput'
diff --git a/src/shared/hooks/useGeneration.ts b/src/shared/hooks/useGeneration.ts
index 36bdbcb9..6f3d3a37 100644
--- a/src/shared/hooks/useGeneration.ts
+++ b/src/shared/hooks/useGeneration.ts
@@ -1,7 +1,7 @@
import { useCallback, useRef } from 'react'
import { useAppStore } from '@shared/stores/appStore'
import { useApi } from './useApi'
-import { showCompletionNotification } from '@shared/utils/notification'
+import { showCompletionNotification, showErrorNotification } from '@shared/utils/notification'
export function useGeneration() {
const { currentJob, setCurrentJob, updateCurrentJob, generationOptions, selectedImageData, pushMeshUrl, clearMeshHistory } = useAppStore()
@@ -53,6 +53,7 @@ export function useGeneration() {
status: 'error',
error: errorMessage
})
+ void showErrorNotification(errorMessage, 'Generation failed')
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps -- useApi re-creates its fns each render, so this re-memoizes anyway (values stay fresh)
@@ -85,6 +86,7 @@ export function useGeneration() {
if (result.status === 'error') {
updateCurrentJob({ status: 'error', error: result.error })
+ void showErrorNotification(result.error ?? 'Unknown error', 'Generation failed')
break
}
diff --git a/src/shared/utils/notification.ts b/src/shared/utils/notification.ts
index 864cd161..e5179974 100644
--- a/src/shared/utils/notification.ts
+++ b/src/shared/utils/notification.ts
@@ -7,7 +7,7 @@
* Skipped when the app window already has focus: the user is looking right at
* it, so a toast on top would just be noise.
*/
-export async function showCompletionNotification(body: string, title = 'Modly'): Promise