|
1 | 1 | <script lang="ts"> |
2 | | - import { getVersionBuilds } from "@/utils/fill"; |
3 | | - import type { Build, ProjectDescriptor } from "@/utils/types"; |
| 2 | + import type { ProjectDescriptor } from "@/utils/types"; |
4 | 3 |
|
5 | 4 | import SoftwareDownloadButton from "@/components/data/SoftwareDownloadButton.svelte"; |
6 | 5 | import SoftwareBuilds from "@/components/data/SoftwareBuilds.svelte"; |
|
10 | 9 | import FoliaIconUrl from "@/assets/brand/folia.svg?url"; |
11 | 10 | import WaterfallIconUrl from "@/assets/brand/waterfall.svg?url"; |
12 | 11 | import type { Snippet } from "svelte"; |
| 12 | + import { fetchBuildsOrError, type ProjectBuildsOrError } from "@/utils/download"; |
| 13 | + import { watch } from "runed"; |
| 14 | +
|
13 | 15 | interface Props { |
14 | 16 | id: "paper" | "velocity" | "folia" | "waterfall" | (string & {}); |
15 | 17 | project: ProjectDescriptor; |
| 18 | + builds: ProjectBuildsOrError; |
16 | 19 | description?: string; |
17 | 20 | Description?: Snippet; |
18 | 21 | experimentalWarning?: string; |
19 | 22 | eol?: boolean; |
20 | 23 | } |
21 | 24 |
|
22 | | - let { id, project, description = undefined, Description = undefined, experimentalWarning = undefined, eol = false }: Props = $props(); |
| 25 | + let { |
| 26 | + id, |
| 27 | + project, |
| 28 | + builds, |
| 29 | + description = undefined, |
| 30 | + Description = undefined, |
| 31 | + experimentalWarning = undefined, |
| 32 | + eol = false, |
| 33 | + }: Props = $props(); |
23 | 34 |
|
24 | 35 | const ICONS: Record<string, string | undefined> = { |
25 | 36 | paper: PaperIconUrl, |
|
32 | 43 |
|
33 | 44 | let version = $derived(isStable ? project?.latestStableVersion : (project?.latestExperimentalVersion ?? project?.latestStableVersion)); |
34 | 45 |
|
35 | | - let builds: Build[] = $state([]); |
36 | | - let latestBuild: Build | undefined = $state(); |
37 | | - let buildsLoading = $state(false); |
38 | | - let buildsError: string | null = $state(null); |
39 | | -
|
40 | | - async function fetchBuilds() { |
41 | | - if (!id || !version) { |
42 | | - builds = []; |
43 | | - latestBuild = undefined; |
44 | | - return; |
45 | | - } |
46 | | - buildsLoading = true; |
47 | | - buildsError = null; |
48 | | - try { |
49 | | - const res = await getVersionBuilds(id, version); |
50 | | - builds = Array.isArray(res) ? res : []; |
51 | | - latestBuild = builds[0] || undefined; |
52 | | - } catch (e) { |
53 | | - console.error(e); |
54 | | - buildsError = `Failed to load builds for ${id} ${version}`; |
55 | | - builds = []; |
56 | | - latestBuild = undefined; |
57 | | - } finally { |
58 | | - buildsLoading = false; |
59 | | - } |
60 | | - } |
61 | | -
|
62 | | - $effect(() => { |
63 | | - fetchBuilds(); |
64 | | - }); |
65 | | -
|
66 | 46 | function toggleStable() { |
67 | 47 | isStable = !isStable; |
68 | 48 | } |
|
72 | 52 | const c = (channel ?? "").toLowerCase(); |
73 | 53 | return `text-channel-${c}-primary`; |
74 | 54 | } |
| 55 | +
|
| 56 | + watch( |
| 57 | + () => version, |
| 58 | + (ver, oldVer) => { |
| 59 | + // Only handle changes, not initial page load where builds are prerendered on server. |
| 60 | + if (oldVer !== undefined && ver !== oldVer) { |
| 61 | + fetchBuildsOrError({ value: project }, !isStable).then((result) => { |
| 62 | + builds = result; |
| 63 | + }); |
| 64 | + } |
| 65 | + } |
| 66 | + ); |
75 | 67 | </script> |
76 | 68 |
|
77 | 69 | <header class="mx-auto flex max-w-7xl flex-row flex-wrap gap-16 px-4 pt-32 pb-16 lg:pt-48 lg:pb-26"> |
|
93 | 85 |
|
94 | 86 | <h2 class="text-4xl leading-normal font-medium lg:text-5xl lg:leading-normal"> |
95 | 87 | Get {project.name} |
96 | | - <span class={channelClass(latestBuild?.channel)}>{version}</span> |
| 88 | + <span class={channelClass(builds?.value?.latest?.channel)}>{version}</span> |
97 | 89 | </h2> |
98 | 90 |
|
99 | 91 | <p class="mt-4 text-xl"> |
|
113 | 105 | </p> |
114 | 106 |
|
115 | 107 | <div class="mt-8 flex flex-col gap-4"> |
116 | | - <SoftwareDownloadButton projectId={id} {project} build={latestBuild} {version} eol={!!eol} disabled={buildsLoading || !latestBuild} /> |
| 108 | + <SoftwareDownloadButton |
| 109 | + projectId={id} |
| 110 | + {project} |
| 111 | + build={builds.value?.latest} |
| 112 | + {version} |
| 113 | + eol={!!eol} |
| 114 | + disabled={builds.value?.latest === null || builds.value?.latest === undefined} |
| 115 | + /> |
117 | 116 |
|
118 | 117 | {#if project.latestExperimentalVersion} |
119 | 118 | <button |
|
143 | 142 | </span> |
144 | 143 | </p> |
145 | 144 |
|
146 | | - {#if buildsLoading} |
147 | | - <div class="text-center text-sm text-gray-400">Loading builds…</div> |
148 | | - {:else if buildsError} |
149 | | - <div class="text-center text-sm text-red-500">{buildsError}</div> |
150 | | - {:else if builds.length > 0} |
151 | | - <SoftwareBuilds project={id} {version} {builds} eol={!!eol} /> |
| 145 | + {#if builds.error} |
| 146 | + <div class="text-center text-sm text-red-500">{builds.error}</div> |
| 147 | + {:else if builds.value && builds.value.builds && builds.value.builds.length > 0} |
| 148 | + <SoftwareBuilds project={id} {version} builds={builds.value.builds} eol={!!eol} /> |
152 | 149 | {/if} |
153 | 150 | </section> |
154 | 151 |
|
|
0 commit comments