diff options
Diffstat (limited to 'web/pw-server')
-rw-r--r-- | web/pw-server/src/lib/components/Leaderboard.svelte | 14 | ||||
-rw-r--r-- | web/pw-server/src/lib/components/navbar/UserControls.svelte | 4 | ||||
-rw-r--r-- | web/pw-server/src/routes/bots/[bot_id].svelte | 74 | ||||
-rw-r--r-- | web/pw-server/src/routes/bots/[bot_name].svelte | 139 | ||||
-rw-r--r-- | web/pw-server/src/routes/users/[user_name].svelte | 25 |
5 files changed, 160 insertions, 96 deletions
diff --git a/web/pw-server/src/lib/components/Leaderboard.svelte b/web/pw-server/src/lib/components/Leaderboard.svelte index 8582198..d29d5d6 100644 --- a/web/pw-server/src/lib/components/Leaderboard.svelte +++ b/web/pw-server/src/lib/components/Leaderboard.svelte @@ -41,11 +41,17 @@ <td class="leaderboard-rating"> {formatRating(entry)} </td> - <td class="leaderboard-bot">{entry["bot"]["name"]}</td> + <td class="leaderboard-bot"> + <a class="leaderboard-href" href="/bots/{entry['bot']['name']}" + >{entry["bot"]["name"]} + </a></td + > <td class="leaderboard-author"> {#if entry["author"]} - <!-- TODO: remove duplication --> - <a href="/users/{entry["author"]["username"]}">{entry["author"]["username"]}</a> + <!-- TODO: remove duplication --> + <a class="leaderboard-href" href="/users/{entry['author']['username']}" + >{entry["author"]["username"]}</a + > {/if} </td> </tr> @@ -71,7 +77,7 @@ color: #333; } - .leaderboard-author a{ + .leaderboard-href { text-decoration: none; color: black; } diff --git a/web/pw-server/src/lib/components/navbar/UserControls.svelte b/web/pw-server/src/lib/components/navbar/UserControls.svelte index a9bd87b..5646982 100644 --- a/web/pw-server/src/lib/components/navbar/UserControls.svelte +++ b/web/pw-server/src/lib/components/navbar/UserControls.svelte @@ -36,8 +36,8 @@ <div class="user-controls"> {#if $currentUser} - <a class="current-user-name" href="/users/{$currentUser["username"]}"> - {$currentUser["username"]} + <a class="current-user-name" href="/users/{$currentUser['username']}"> + {$currentUser["username"]} </a> <div class="sign-out" on:click={signOut}>Sign out</div> {:else} diff --git a/web/pw-server/src/routes/bots/[bot_id].svelte b/web/pw-server/src/routes/bots/[bot_id].svelte deleted file mode 100644 index 3eece10..0000000 --- a/web/pw-server/src/routes/bots/[bot_id].svelte +++ /dev/null @@ -1,74 +0,0 @@ -<script lang="ts" context="module"> - import { get_session_token } from "$lib/auth"; - - export async function load({ page }) { - const token = get_session_token(); - const res = await fetch(`/api/bots/${page.params["bot_id"]}`, { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${token}`, - }, - }); - - if (res.ok) { - const data = await res.json(); - return { - props: { - bot: data["bot"], - bundles: data["bundles"], - }, - }; - } - - return { - status: res.status, - error: new Error("Could not load bot"), - }; - } -</script> - -<script lang="ts"> - import dayjs from "dayjs"; - - export let bot: object; - export let bundles: object[]; - - let files; - - async function submitCode() { - console.log("click"); - const token = get_session_token(); - - const formData = new FormData(); - formData.append("File", files[0]); - - const res = await fetch(`/api/bots/${bot["id"]}/upload`, { - method: "POST", - headers: { - // the content type header will be set by the browser - Authorization: `Bearer ${token}`, - }, - body: formData, - }); - - console.log(res.statusText); - } -</script> - -<div> - {bot["name"]} -</div> - -<div>Upload code</div> -<form on:submit|preventDefault={submitCode}> - <input type="file" bind:files /> - <button type="submit">Submit</button> -</form> - -<ul> - {#each bundles as bundle} - <li> - bundle created at {dayjs(bundle["created_at"]).format("YYYY-MM-DD HH:mm")} - </li> - {/each} -</ul> diff --git a/web/pw-server/src/routes/bots/[bot_name].svelte b/web/pw-server/src/routes/bots/[bot_name].svelte new file mode 100644 index 0000000..9e9f016 --- /dev/null +++ b/web/pw-server/src/routes/bots/[bot_name].svelte @@ -0,0 +1,139 @@ +<script lang="ts" context="module"> + import { get_session_token } from "$lib/auth"; + + export async function load({ params, fetch }) { + const token = get_session_token(); + const res = await fetch(`/api/bots/${params["bot_name"]}`, { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + if (res.ok) { + const { bot, owner, versions } = await res.json(); + // sort most recent first + versions.sort((a: string, b: string) => + dayjs(a["created_at"]).isAfter(b["created_at"]) ? -1 : 1 + ); + return { + props: { + bot, + owner, + versions, + }, + }; + } + + return { + status: res.status, + error: new Error("Could not find bot"), + }; + } +</script> + +<script lang="ts"> + import dayjs from "dayjs"; + + import { currentUser } from "$lib/stores/current_user"; + + export let bot: object; + export let owner: object; + export let versions: object[]; + + // function last_updated() { + // versions.sort() + // } + + // let files; + + // async function submitCode() { + // console.log("click"); + // const token = get_session_token(); + + // const formData = new FormData(); + // formData.append("File", files[0]); + + // const res = await fetch(`/api/bots/${bot["id"]}/upload`, { + // method: "POST", + // headers: { + // // the content type header will be set by the browser + // Authorization: `Bearer ${token}`, + // }, + // body: formData, + // }); + + // console.log(res.statusText); + // } +</script> + +<!-- +<div>Upload code</div> +<form on:submit|preventDefault={submitCode}> + <input type="file" bind:files /> + <button type="submit">Submit</button> +</form> --> + +<div class="container"> + <div class="header"> + <h1 class="bot-name">{bot["name"]}</h1> + {#if owner} + <a class="owner-name" href="/users/{owner['username']}"> + {owner["username"]} + </a> + {/if} + </div> + + {#if $currentUser && $currentUser["user_id"] === bot["owner_id"]} + <div> + <!-- TODO: can we avoid hardcoding the url? --> + Publish a new version by pushing a docker container to + <code>registry.planetwars.dev/{bot["name"]}:latest</code>, or using the web editor. + </div> + {/if} + + <div class="versions"> + <h4>Versions</h4> + <ul class="version-list"> + {#each versions as version} + <li> + {dayjs(version["created_at"]).format("YYYY-MM-DD HH:mm")} + </li> + {/each} + </ul> + </div> +</div> + +<style lang="scss"> + .container { + width: 800px; + max-width: 80%; + margin: 50px auto; + } + + .header { + display: flex; + justify-content: space-between; + align-items: flex-end; + margin-bottom: 60px; + border-bottom: 1px solid black; + } + + $header-space-above-line: 12px; + + .bot-name { + font-size: 24pt; + margin-bottom: $header-space-above-line; + } + + .owner-name { + font-size: 14pt; + text-decoration: none; + color: #333; + margin-bottom: $header-space-above-line; + } + + .versions { + margin: 30px 0; + } +</style> diff --git a/web/pw-server/src/routes/users/[user_name].svelte b/web/pw-server/src/routes/users/[user_name].svelte index fab3a96..a1801f4 100644 --- a/web/pw-server/src/routes/users/[user_name].svelte +++ b/web/pw-server/src/routes/users/[user_name].svelte @@ -1,12 +1,4 @@ <script lang="ts" context="module"> - function fetchJson(url: string): Promise<Response> { - return fetch(url, { - headers: { - "Content-Type": "application/json", - }, - }); - } - export async function load({ params, fetch }) { const userName = params["user_name"]; const userBotsResponse = await fetch(`/api/users/${userName}/bots`); @@ -36,17 +28,17 @@ <h2>Bots</h2> <ul class="bot-list"> {#each bots as bot} - <li class="bot"> - <span class="bot-name">{bot['name']}</span> - </li> + <li class="bot"> + <a class="bot-name" href="/bots/{bot['name']}">{bot["name"]}</a> + </li> {/each} </ul> </div> <style lang="scss"> .container { - min-width: 600px; - max-width: 800px; + width: 800px; + max-width: 80%; margin: 50px auto; } @@ -56,7 +48,7 @@ } .user-name { - margin-bottom: .5em; + margin-bottom: 0.5em; } .bot-list { @@ -75,10 +67,11 @@ .bot-name { font-size: 20px; font-weight: 400; + text-decoration: none; + color: black; } .bot:first-child { border-top: 1px solid $border-color; } - -</style>
\ No newline at end of file +</style> |