|
29 | 29 | let artists = $state([]); |
30 | 30 | let loading = $state(false); |
31 | 31 | let result = $state(null); |
| 32 | + let error = $state(''); |
32 | 33 | let loadPromise = null; |
33 | 34 |
|
34 | 35 | async function loadArtists() { |
35 | 36 | if (artists.length) return artists; |
36 | | - if (!loadPromise) loadPromise = fetch('./data/artist_index.json').then((r) => r.json()); |
| 37 | + if (!loadPromise) { |
| 38 | + loadPromise = fetch(`${import.meta.env.BASE_URL}data/artist_index.json`).then((response) => { |
| 39 | + if (!response.ok) throw new Error(`Could not load artist index (${response.status})`); |
| 40 | + return response.json(); |
| 41 | + }); |
| 42 | + } |
37 | 43 | artists = await loadPromise; |
38 | 44 | return artists; |
39 | 45 | } |
40 | 46 |
|
41 | 47 | function chooseDecade(range) { |
42 | 48 | answers = { ...answers, decadeRange: range }; |
43 | | - window.setTimeout(() => (stage = 1), 200); |
| 49 | + stage = 1; |
44 | 50 | } |
45 | 51 |
|
46 | 52 | function chooseRegion(region) { |
47 | 53 | answers = { ...answers, region }; |
48 | | - window.setTimeout(() => (stage = 2), 200); |
| 54 | + stage = 2; |
49 | 55 | } |
50 | 56 |
|
51 | 57 | async function chooseMedium(medium) { |
52 | 58 | answers = { ...answers, medium }; |
53 | 59 | stage = 3; |
54 | 60 | loading = true; |
| 61 | + error = ''; |
55 | 62 | const started = performance.now(); |
56 | | - const loaded = await loadArtists(); |
57 | | - const elapsed = performance.now() - started; |
58 | | - if (elapsed < 600) await new Promise((resolve) => window.setTimeout(resolve, 600 - elapsed)); |
59 | | - result = matchArtist(loaded, { ...answers, medium }); |
60 | | - loading = false; |
61 | | - stage = 3; |
| 63 | + try { |
| 64 | + const loaded = await loadArtists(); |
| 65 | + const elapsed = performance.now() - started; |
| 66 | + if (elapsed < 600) await new Promise((resolve) => window.setTimeout(resolve, 600 - elapsed)); |
| 67 | + result = matchArtist(loaded, { ...answers, medium }); |
| 68 | + } catch { |
| 69 | + error = 'The artist index could not be loaded. Please refresh the page or run the site through Vite.'; |
| 70 | + } finally { |
| 71 | + loading = false; |
| 72 | + stage = 3; |
| 73 | + } |
62 | 74 | } |
63 | 75 |
|
64 | 76 | function reset() { |
65 | 77 | stage = 0; |
66 | 78 | answers = { decadeRange: null, region: '', medium: '' }; |
67 | 79 | result = null; |
68 | 80 | loading = false; |
| 81 | + error = ''; |
69 | 82 | } |
70 | 83 |
|
71 | 84 | function lifespan(artist) { |
|
86 | 99 | .map((part) => part[0]) |
87 | 100 | .join(''); |
88 | 101 | } |
| 102 | +
|
| 103 | + function resultPrompt() { |
| 104 | + if (stage === 0) return 'Step 1 of 3: choose a decade.'; |
| 105 | + if (stage === 1) return 'Decade saved. Pick a region next.'; |
| 106 | + if (stage === 2) return 'Almost there. Pick a medium to get your match.'; |
| 107 | + return 'Your artist match will appear here.'; |
| 108 | + } |
89 | 109 | </script> |
90 | 110 |
|
91 | 111 | <section class="scene-quiz" aria-labelledby="scene-5-title"> |
|
151 | 171 | <span></span> |
152 | 172 | <p>Finding someone for you...</p> |
153 | 173 | </div> |
| 174 | + {:else if error} |
| 175 | + <div class="empty-result"> |
| 176 | + <div class="portrait preview" aria-hidden="true">!</div> |
| 177 | + <p>{error}</p> |
| 178 | + <button type="button" onclick={reset}>Try again</button> |
| 179 | + </div> |
154 | 180 | {:else if result?.artist} |
155 | 181 | <article class="result"> |
156 | 182 | {#if result.relaxed} |
|
196 | 222 | {:else} |
197 | 223 | <div class="empty-result"> |
198 | 224 | <div class="portrait preview" aria-hidden="true">?</div> |
199 | | - <p>Your artist match will appear here.</p> |
| 225 | + <p>{resultPrompt()}</p> |
200 | 226 | </div> |
201 | 227 | {/if} |
202 | 228 | </aside> |
|
0 commit comments