Enhance image upload experience in ReceiptForm and +page components by integrating a loading state with a spinner icon during image processing. Update styles for better accessibility and user feedback, ensuring a smoother interaction when converting images to WebP format.
CI / build (push) Has been skipped
CI / deploy (push) Successful in 1m33s

This commit is contained in:
eewing
2026-02-19 11:33:57 -06:00
parent 8af1ee8bd4
commit d06e585bb5
18 changed files with 184 additions and 145 deletions
+6 -6
View File
@@ -1,6 +1,7 @@
import {
Icon_default
} from "./chunk-SK3R2OSP.js";
} from "./chunk-V6DNLLKF.js";
import "./chunk-2LGM3QYM.js";
import {
check_target,
hmr,
@@ -9,11 +10,12 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
append,
comment
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
FILENAME,
HMR,
@@ -22,12 +24,10 @@ import {
noop,
pop,
push
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/check.svelte
+6 -6
View File
@@ -1,6 +1,7 @@
import {
Icon_default
} from "./chunk-SK3R2OSP.js";
} from "./chunk-V6DNLLKF.js";
import "./chunk-2LGM3QYM.js";
import {
check_target,
hmr,
@@ -9,11 +10,12 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
append,
comment
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
FILENAME,
HMR,
@@ -22,12 +24,10 @@ import {
noop,
pop,
push
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/chevron-right.svelte
+6 -6
View File
@@ -1,6 +1,7 @@
import {
Icon_default
} from "./chunk-SK3R2OSP.js";
} from "./chunk-V6DNLLKF.js";
import "./chunk-2LGM3QYM.js";
import {
check_target,
hmr,
@@ -9,11 +10,12 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
append,
comment
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
FILENAME,
HMR,
@@ -22,12 +24,10 @@ import {
noop,
pop,
push
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/circle.svelte
+6 -6
View File
@@ -1,6 +1,7 @@
import {
Icon_default
} from "./chunk-SK3R2OSP.js";
} from "./chunk-V6DNLLKF.js";
import "./chunk-2LGM3QYM.js";
import {
check_target,
hmr,
@@ -9,11 +10,12 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
append,
comment
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
FILENAME,
HMR,
@@ -22,12 +24,10 @@ import {
noop,
pop,
push
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/minus.svelte
+6 -6
View File
@@ -1,6 +1,7 @@
import {
Icon_default
} from "./chunk-SK3R2OSP.js";
} from "./chunk-V6DNLLKF.js";
import "./chunk-2LGM3QYM.js";
import {
check_target,
hmr,
@@ -9,11 +10,12 @@ import {
snippet,
spread_props,
wrap_snippet
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
append,
comment
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
FILENAME,
HMR,
@@ -22,12 +24,10 @@ import {
noop,
pop,
push
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-2LGM3QYM.js";
import "./chunk-LYA4E26T.js";
// node_modules/@lucide/svelte/dist/icons/x.svelte
+63 -57
View File
@@ -2,30 +2,30 @@
"hash": "e1b6cade",
"configHash": "441370a6",
"lockfileHash": "9401e68b",
"browserHash": "c578848f",
"browserHash": "8eb13a4f",
"optimized": {
"svelte": {
"src": "../../svelte/src/index-client.js",
"file": "svelte.js",
"fileHash": "836a0569",
"fileHash": "07b115b9",
"needsInterop": false
},
"svelte/animate": {
"src": "../../svelte/src/animate/index.js",
"file": "svelte_animate.js",
"fileHash": "a84129da",
"fileHash": "c012b289",
"needsInterop": false
},
"svelte/attachments": {
"src": "../../svelte/src/attachments/index.js",
"file": "svelte_attachments.js",
"fileHash": "2242f01b",
"fileHash": "6bded66c",
"needsInterop": false
},
"svelte/easing": {
"src": "../../svelte/src/easing/index.js",
"file": "svelte_easing.js",
"fileHash": "0123c7d6",
"fileHash": "8c8820c0",
"needsInterop": false
},
"svelte/internal": {
@@ -37,220 +37,226 @@
"svelte/internal/client": {
"src": "../../svelte/src/internal/client/index.js",
"file": "svelte_internal_client.js",
"fileHash": "bf7d241e",
"fileHash": "c34b6da3",
"needsInterop": false
},
"svelte/internal/disclose-version": {
"src": "../../svelte/src/internal/disclose-version.js",
"file": "svelte_internal_disclose-version.js",
"fileHash": "5ac70717",
"fileHash": "9a06bc8d",
"needsInterop": false
},
"svelte/internal/flags/async": {
"src": "../../svelte/src/internal/flags/async.js",
"file": "svelte_internal_flags_async.js",
"fileHash": "1b74e6fc",
"fileHash": "61336ace",
"needsInterop": false
},
"svelte/internal/flags/legacy": {
"src": "../../svelte/src/internal/flags/legacy.js",
"file": "svelte_internal_flags_legacy.js",
"fileHash": "1c59baa5",
"fileHash": "b5bf1ecd",
"needsInterop": false
},
"svelte/internal/flags/tracing": {
"src": "../../svelte/src/internal/flags/tracing.js",
"file": "svelte_internal_flags_tracing.js",
"fileHash": "6a43fbc1",
"fileHash": "3fd00f44",
"needsInterop": false
},
"svelte/legacy": {
"src": "../../svelte/src/legacy/legacy-client.js",
"file": "svelte_legacy.js",
"fileHash": "f44ad964",
"fileHash": "3de6d8ec",
"needsInterop": false
},
"svelte/motion": {
"src": "../../svelte/src/motion/index.js",
"file": "svelte_motion.js",
"fileHash": "eed1a42f",
"fileHash": "d56675c0",
"needsInterop": false
},
"svelte/reactivity": {
"src": "../../svelte/src/reactivity/index-client.js",
"file": "svelte_reactivity.js",
"fileHash": "8addd267",
"fileHash": "699399e6",
"needsInterop": false
},
"svelte/reactivity/window": {
"src": "../../svelte/src/reactivity/window/index.js",
"file": "svelte_reactivity_window.js",
"fileHash": "cb259eae",
"fileHash": "a0847fd2",
"needsInterop": false
},
"svelte/store": {
"src": "../../svelte/src/store/index-client.js",
"file": "svelte_store.js",
"fileHash": "8719f5c5",
"fileHash": "14d7ddb4",
"needsInterop": false
},
"svelte/transition": {
"src": "../../svelte/src/transition/index.js",
"file": "svelte_transition.js",
"fileHash": "6d4c0f07",
"fileHash": "423bf8f4",
"needsInterop": false
},
"svelte/events": {
"src": "../../svelte/src/events/index.js",
"file": "svelte_events.js",
"fileHash": "ec738ae4",
"fileHash": "078c4a8c",
"needsInterop": false
},
"svelte > clsx": {
"src": "../../clsx/dist/clsx.mjs",
"file": "svelte___clsx.js",
"fileHash": "a84375a2",
"fileHash": "1ee833c7",
"needsInterop": false
},
"@lucide/svelte/icons/check": {
"src": "../../@lucide/svelte/dist/icons/check.js",
"file": "@lucide_svelte_icons_check.js",
"fileHash": "cc59c42d",
"fileHash": "0ac209ae",
"needsInterop": false
},
"@lucide/svelte/icons/chevron-right": {
"src": "../../@lucide/svelte/dist/icons/chevron-right.js",
"file": "@lucide_svelte_icons_chevron-right.js",
"fileHash": "4ebfe37c",
"fileHash": "c09b9f4f",
"needsInterop": false
},
"@lucide/svelte/icons/circle": {
"src": "../../@lucide/svelte/dist/icons/circle.js",
"file": "@lucide_svelte_icons_circle.js",
"fileHash": "c9116309",
"fileHash": "e48abf24",
"needsInterop": false
},
"@lucide/svelte/icons/minus": {
"src": "../../@lucide/svelte/dist/icons/minus.js",
"file": "@lucide_svelte_icons_minus.js",
"fileHash": "e38affc6",
"fileHash": "cbdf943d",
"needsInterop": false
},
"@lucide/svelte/icons/x": {
"src": "../../@lucide/svelte/dist/icons/x.js",
"file": "@lucide_svelte_icons_x.js",
"fileHash": "dd4ef7b8",
"fileHash": "32d222b0",
"needsInterop": false
},
"barcode-detector-api-polyfill": {
"src": "../../barcode-detector-api-polyfill/esm/index.js",
"file": "barcode-detector-api-polyfill.js",
"fileHash": "e171d6a3",
"fileHash": "44de5b82",
"needsInterop": false
},
"bits-ui": {
"src": "../../bits-ui/dist/index.js",
"file": "bits-ui.js",
"fileHash": "79f12900",
"fileHash": "9adf7bd3",
"needsInterop": false
},
"clsx": {
"src": "../../clsx/dist/clsx.mjs",
"file": "clsx.js",
"fileHash": "2d2f5d80",
"fileHash": "6547c390",
"needsInterop": false
},
"devalue": {
"src": "../../devalue/index.js",
"file": "devalue.js",
"fileHash": "d36225a1",
"fileHash": "6bd276fd",
"needsInterop": false
},
"esm-env": {
"src": "../../esm-env/index.js",
"file": "esm-env.js",
"fileHash": "b2a3e5c0",
"fileHash": "a16abac7",
"needsInterop": false
},
"pocketbase": {
"src": "../../pocketbase/dist/pocketbase.es.mjs",
"file": "pocketbase.js",
"fileHash": "d86e8c93",
"fileHash": "241d5081",
"needsInterop": false
},
"tailwind-merge": {
"src": "../../tailwind-merge/dist/bundle-mjs.mjs",
"file": "tailwind-merge.js",
"fileHash": "5a4842de",
"fileHash": "7d5f8442",
"needsInterop": false
},
"tailwind-variants": {
"src": "../../tailwind-variants/dist/index.js",
"file": "tailwind-variants.js",
"fileHash": "af3e226f",
"fileHash": "3821161a",
"needsInterop": false
},
"@lucide/svelte/icons/chevron-down": {
"src": "../../@lucide/svelte/dist/icons/chevron-down.js",
"file": "@lucide_svelte_icons_chevron-down.js",
"fileHash": "c086c4f6",
"fileHash": "48902207",
"needsInterop": false
},
"@lucide/svelte/icons/chevron-up": {
"src": "../../@lucide/svelte/dist/icons/chevron-up.js",
"file": "@lucide_svelte_icons_chevron-up.js",
"fileHash": "8f687e14",
"fileHash": "b33cd26c",
"needsInterop": false
},
"heic2any": {
"src": "../../heic2any/dist/heic2any.js",
"file": "heic2any.js",
"fileHash": "fb3f1ac6",
"fileHash": "4e438dea",
"needsInterop": true
},
"@lucide/svelte/icons/loader-2": {
"src": "../../@lucide/svelte/dist/icons/loader-2.js",
"file": "@lucide_svelte_icons_loader-2.js",
"fileHash": "7eba973c",
"needsInterop": false
}
},
"chunks": {
"chunk-2KB4Y67V": {
"file": "chunk-2KB4Y67V.js"
"chunk-N4HEU72H": {
"file": "chunk-N4HEU72H.js"
},
"chunk-UKQGYTAZ": {
"file": "chunk-UKQGYTAZ.js"
"chunk-MPD7DSJG": {
"file": "chunk-MPD7DSJG.js"
},
"chunk-7RQDXF5S": {
"file": "chunk-7RQDXF5S.js"
},
"chunk-MZVN5SDE": {
"file": "chunk-MZVN5SDE.js"
"chunk-V6DNLLKF": {
"file": "chunk-V6DNLLKF.js"
},
"chunk-SK3R2OSP": {
"file": "chunk-SK3R2OSP.js"
"chunk-2LGM3QYM": {
"file": "chunk-2LGM3QYM.js"
},
"chunk-HRPYXN4O": {
"file": "chunk-HRPYXN4O.js"
"chunk-NTAG77ZX": {
"file": "chunk-NTAG77ZX.js"
},
"chunk-XGKSMLPM": {
"file": "chunk-XGKSMLPM.js"
},
"chunk-7XW5QO7S": {
"file": "chunk-7XW5QO7S.js"
},
"chunk-SWXNV5Y3": {
"file": "chunk-SWXNV5Y3.js"
},
"chunk-XWATFG4W": {
"file": "chunk-XWATFG4W.js"
"chunk-MKTP2BFS": {
"file": "chunk-MKTP2BFS.js"
},
"chunk-U7P2NEEE": {
"file": "chunk-U7P2NEEE.js"
},
"chunk-HZ6NBROY": {
"file": "chunk-HZ6NBROY.js"
},
"chunk-XWATFG4W": {
"file": "chunk-XWATFG4W.js"
},
"chunk-HNWPC2PS": {
"file": "chunk-HNWPC2PS.js"
},
"chunk-MZVN5SDE": {
"file": "chunk-MZVN5SDE.js"
},
"chunk-OHYQYV5R": {
"file": "chunk-OHYQYV5R.js"
},
"chunk-2LGM3QYM": {
"file": "chunk-2LGM3QYM.js"
"chunk-HRPYXN4O": {
"file": "chunk-HRPYXN4O.js"
},
"chunk-YERFD2CZ": {
"file": "chunk-YERFD2CZ.js"
+10 -10
View File
@@ -1,9 +1,9 @@
import {
SvelteMap
} from "./chunk-2KB4Y67V.js";
import "./chunk-UKQGYTAZ.js";
} from "./chunk-N4HEU72H.js";
import "./chunk-MPD7DSJG.js";
import "./chunk-7RQDXF5S.js";
import "./chunk-MZVN5SDE.js";
import "./chunk-2LGM3QYM.js";
import {
add_locations,
append_styles,
@@ -38,7 +38,7 @@ import {
validate_snippet_args,
validate_void_dynamic_element,
wrap_snippet
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
append,
comment,
@@ -49,7 +49,10 @@ import {
set_text,
text,
unmount
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import {
clsx
} from "./chunk-U7P2NEEE.js";
import {
FILENAME,
HMR,
@@ -85,16 +88,13 @@ import {
user_derived,
user_effect,
user_pre_effect
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import {
clsx
} from "./chunk-U7P2NEEE.js";
import {
true_default
} from "./chunk-HNWPC2PS.js";
import "./chunk-MZVN5SDE.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-2LGM3QYM.js";
import {
__export,
__privateAdd,
+4 -4
View File
@@ -7,12 +7,13 @@ import {
hydratable,
onDestroy,
onMount
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
hydrate,
mount,
unmount
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
createContext,
flushSync,
@@ -24,9 +25,8 @@ import {
settled,
tick,
untrack
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-LYA4E26T.js";
+4 -4
View File
@@ -1,11 +1,11 @@
import {
createAttachmentKey,
fromAction
} from "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import "./chunk-SWXNV5Y3.js";
import "./chunk-XWATFG4W.js";
} from "./chunk-NTAG77ZX.js";
import "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-LYA4E26T.js";
+1 -1
View File
@@ -1,7 +1,7 @@
import "./chunk-7RQDXF5S.js";
import {
on
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
+4 -4
View File
@@ -107,7 +107,7 @@ import {
validate_store,
validate_void_dynamic_element,
wrap_snippet
} from "./chunk-XGKSMLPM.js";
} from "./chunk-NTAG77ZX.js";
import {
append,
comment,
@@ -125,7 +125,8 @@ import {
text,
trusted,
with_script
} from "./chunk-7XW5QO7S.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
$document,
$window,
@@ -199,9 +200,8 @@ import {
user_effect,
user_pre_effect,
wait
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-LYA4E26T.js";
+2 -2
View File
@@ -12,8 +12,8 @@ import {
stopImmediatePropagation,
stopPropagation,
trusted
} from "./chunk-7XW5QO7S.js";
import "./chunk-SWXNV5Y3.js";
} from "./chunk-MKTP2BFS.js";
import "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
+6 -6
View File
@@ -1,14 +1,15 @@
import {
MediaQuery
} from "./chunk-2KB4Y67V.js";
import "./chunk-UKQGYTAZ.js";
} from "./chunk-N4HEU72H.js";
import "./chunk-MPD7DSJG.js";
import "./chunk-7RQDXF5S.js";
import {
loop,
raf,
writable
} from "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
} from "./chunk-NTAG77ZX.js";
import "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
deferred,
get,
@@ -17,9 +18,8 @@ import {
set,
state,
tag
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import {
true_default
} from "./chunk-HNWPC2PS.js";
+6 -6
View File
@@ -5,16 +5,16 @@ import {
SvelteSet,
SvelteURL,
SvelteURLSearchParams
} from "./chunk-2KB4Y67V.js";
import "./chunk-UKQGYTAZ.js";
} from "./chunk-N4HEU72H.js";
import "./chunk-MPD7DSJG.js";
import "./chunk-7RQDXF5S.js";
import "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import "./chunk-NTAG77ZX.js";
import "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
createSubscriber
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-LYA4E26T.js";
+5 -5
View File
@@ -1,18 +1,18 @@
import {
ReactiveValue
} from "./chunk-UKQGYTAZ.js";
} from "./chunk-MPD7DSJG.js";
import "./chunk-7RQDXF5S.js";
import "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
import "./chunk-NTAG77ZX.js";
import "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
get,
on,
set,
source,
tag
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import {
true_default
} from "./chunk-HNWPC2PS.js";
+4 -4
View File
@@ -4,8 +4,9 @@ import {
readable,
readonly,
writable
} from "./chunk-XGKSMLPM.js";
import "./chunk-7XW5QO7S.js";
} from "./chunk-NTAG77ZX.js";
import "./chunk-MKTP2BFS.js";
import "./chunk-U7P2NEEE.js";
import {
active_effect,
active_reaction,
@@ -15,9 +16,8 @@ import {
render_effect,
set_active_effect,
set_active_reaction
} from "./chunk-SWXNV5Y3.js";
} from "./chunk-HZ6NBROY.js";
import "./chunk-XWATFG4W.js";
import "./chunk-U7P2NEEE.js";
import "./chunk-HNWPC2PS.js";
import "./chunk-OHYQYV5R.js";
import "./chunk-LYA4E26T.js";
+17 -3
View File
@@ -3,9 +3,13 @@
import { Label } from "$lib/components/ui/label";
import { convertImageToWebP } from "$lib/convert-image-to-webp";
import { enhance } from "$app/forms";
import Loader2Icon from "@lucide/svelte/icons/loader-2";
const TYPE_OPTIONS = ["Purchase", "Gas"] as const;
const SCAN_BUTTON_CLASS =
"border-input bg-background hover:bg-accent hover:text-accent-foreground flex h-9 w-full cursor-pointer items-center justify-center gap-2 rounded-md border px-4 py-2 text-sm font-medium shadow-xs transition-colors";
let {
action,
submitLabel,
@@ -32,6 +36,8 @@
}
imageConverting = true;
imageFileName = null;
// Let the UI paint "Processing image…" before we block the main thread
await new Promise((r) => setTimeout(r, 0));
try {
const webpFile = await convertImageToWebP(file);
const dt = new DataTransfer();
@@ -86,12 +92,20 @@
tabindex="-1"
aria-label="Scan receipt"
/>
<label
for="Image"
class="border-input bg-background hover:bg-accent hover:text-accent-foreground flex h-9 w-full cursor-pointer items-center justify-center rounded-md border px-4 py-2 text-sm font-medium shadow-xs transition-colors"
{#if imageConverting}
<div
class="{SCAN_BUTTON_CLASS} pointer-events-none opacity-80"
aria-busy="true"
aria-live="polite"
>
<Loader2Icon class="size-4 shrink-0 animate-spin" aria-hidden />
<span>Processing image…</span>
</div>
{:else}
<label for="Image" class={SCAN_BUTTON_CLASS}>
Scan receipt
</label>
{/if}
{#if imageConverting}
<p class="text-muted-foreground text-xs">Converting to WebP…</p>
{:else if imageFileName}
+19
View File
@@ -9,6 +9,7 @@
import { enhance } from "$app/forms";
import ChevronDownIcon from "@lucide/svelte/icons/chevron-down";
import ChevronUpIcon from "@lucide/svelte/icons/chevron-up";
import Loader2Icon from "@lucide/svelte/icons/loader-2";
import type { StackqReceipt } from "$lib/types/receipts";
import type { ReceiptLineItem } from "$lib/types/receipts";
@@ -122,6 +123,7 @@
let imageFileName = $state<string | null>(null);
let selectedImageFile = $state<File | null>(null);
let imageError = $state(false);
let imageConverting = $state(false);
/** On small screens image is collapsed by default; on lg+ expanded. */
let imageOpen = $state(false);
@@ -141,6 +143,10 @@
imageFileName = null;
return;
}
imageConverting = true;
selectedImageFile = null;
imageFileName = null;
await new Promise((r) => setTimeout(r, 0));
try {
const webpFile = await convertImageToWebP(file);
selectedImageFile = webpFile;
@@ -149,6 +155,8 @@
selectedImageFile = null;
imageFileName = null;
if (input) input.value = "";
} finally {
imageConverting = false;
}
}
function imageLoadError() {
@@ -247,12 +255,23 @@
tabindex="-1"
aria-label={receipt.Image ? "Replace image" : "Add image"}
/>
{#if imageConverting}
<div
class="border-input bg-background inline-flex h-8 cursor-not-allowed items-center justify-center gap-2 rounded-md border px-3 text-sm font-medium opacity-80"
aria-busy="true"
aria-live="polite"
>
<Loader2Icon class="size-4 shrink-0 animate-spin" aria-hidden />
<span>Processing image…</span>
</div>
{:else}
<label
for="receipt-image-input"
class="border-input bg-background hover:bg-accent hover:text-accent-foreground inline-flex h-8 cursor-pointer items-center justify-center rounded-md border px-3 text-sm font-medium shadow-xs transition-colors"
>
{receipt.Image ? "Replace image" : "Add image"}
</label>
{/if}
{#if imageFileName}
<span class="text-muted-foreground text-xs">New: {imageFileName}</span>
{/if}