Skeleton: Fetch static data (teams/drivers/races/substitutions) in global layout asynchronously
All checks were successful
Build Formula11 Docker Image / pocketbase-docker (push) Successful in 29s
All checks were successful
Build Formula11 Docker Image / pocketbase-docker (push) Successful in 29s
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
|
import type { Driver, Graphic, Race, Substitution, Team } from "$lib/schema";
|
||||||
import type { LayoutServerLoad } from "./$types";
|
import type { LayoutServerLoad } from "./$types";
|
||||||
|
|
||||||
// On each page load (every route), this function runs serverside.
|
// On each page load (every route), this function runs serverside.
|
||||||
@ -6,14 +7,82 @@ import type { LayoutServerLoad } from "./$types";
|
|||||||
// It will populate the "user" attribute of each page's "data" object,
|
// It will populate the "user" attribute of each page's "data" object,
|
||||||
// so each page has access to the current user (or knows if no one is signed in).
|
// so each page has access to the current user (or knows if no one is signed in).
|
||||||
export const load: LayoutServerLoad = ({ locals }) => {
|
export const load: LayoutServerLoad = ({ locals }) => {
|
||||||
if (locals.user) {
|
const fetch_graphics = async (): Promise<Graphic[]> => {
|
||||||
return {
|
const graphics: Graphic[] = await locals.pb
|
||||||
user: locals.user,
|
.collection("graphics")
|
||||||
admin: locals.user.admin,
|
.getFullList({ fetch: fetch });
|
||||||
};
|
|
||||||
}
|
graphics.map((graphic: Graphic) => {
|
||||||
|
graphic.file_url = locals.pb.files.getURL(graphic, graphic.file);
|
||||||
|
});
|
||||||
|
|
||||||
|
return graphics;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetch_teams = async (): Promise<Team[]> => {
|
||||||
|
const teams: Team[] = await locals.pb.collection("teams").getFullList({
|
||||||
|
sort: "+name",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
teams.map((team: Team) => {
|
||||||
|
team.banner_url = locals.pb.files.getURL(team, team.banner);
|
||||||
|
team.logo_url = locals.pb.files.getURL(team, team.logo);
|
||||||
|
});
|
||||||
|
|
||||||
|
return teams;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetch_drivers = async (): Promise<Driver[]> => {
|
||||||
|
const drivers: Driver[] = await locals.pb.collection("drivers").getFullList({
|
||||||
|
sort: "+code",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
drivers.map((driver: Driver) => {
|
||||||
|
driver.headshot_url = locals.pb.files.getURL(driver, driver.headshot);
|
||||||
|
});
|
||||||
|
|
||||||
|
return drivers;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetch_races = async (): Promise<Race[]> => {
|
||||||
|
const races: Race[] = await locals.pb.collection("races").getFullList({
|
||||||
|
sort: "+step",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
races.map((race: Race) => {
|
||||||
|
race.pictogram_url = locals.pb.files.getURL(race, race.pictogram);
|
||||||
|
});
|
||||||
|
|
||||||
|
return races;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetch_substitutions = async (): Promise<Substitution[]> => {
|
||||||
|
const substitutions: Substitution[] = await locals.pb.collection("substitutions").getFullList({
|
||||||
|
expand: "race",
|
||||||
|
fetch: fetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort by race step (ascending)
|
||||||
|
substitutions.sort(
|
||||||
|
(a: Substitution, b: Substitution) => a.expand.race.step - b.expand.race.step,
|
||||||
|
);
|
||||||
|
|
||||||
|
return substitutions;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: undefined,
|
// User information
|
||||||
|
user: locals.user,
|
||||||
|
admin: locals.user?.admin ?? false,
|
||||||
|
|
||||||
|
// Return static data asynchronously
|
||||||
|
graphics: fetch_graphics(),
|
||||||
|
teams: fetch_teams(),
|
||||||
|
drivers: fetch_drivers(),
|
||||||
|
races: fetch_races(),
|
||||||
|
substitutions: fetch_substitutions(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -49,51 +49,7 @@ export const load: PageServerLoad = async ({ fetch, locals }) => {
|
|||||||
return raceresults;
|
return raceresults;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Duplicated code from data/season/+layout.server.ts and racepicks/+page.server.ts
|
|
||||||
const fetch_races = async (): Promise<Race[]> => {
|
|
||||||
const races: Race[] = await locals.pb.collection("races").getFullList({
|
|
||||||
sort: "+step",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
races.map((race: Race) => {
|
|
||||||
race.pictogram_url = locals.pb.files.getURL(race, race.pictogram);
|
|
||||||
});
|
|
||||||
|
|
||||||
return races;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Duplicated code from data/season/+layout.server.ts and racepicks/+page.server.ts
|
|
||||||
const fetch_drivers = async (): Promise<Driver[]> => {
|
|
||||||
const drivers: Driver[] = await locals.pb.collection("drivers").getFullList({
|
|
||||||
sort: "+code",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
drivers.map((driver: Driver) => {
|
|
||||||
driver.headshot_url = locals.pb.files.getURL(driver, driver.headshot);
|
|
||||||
});
|
|
||||||
|
|
||||||
return drivers;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Duplicated code from racepicks/+page.server.ts + users/+page.server.ts
|
|
||||||
const fetch_graphics = async (): Promise<Graphic[]> => {
|
|
||||||
const graphics: Graphic[] = await locals.pb
|
|
||||||
.collection("graphics")
|
|
||||||
.getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
graphics.map((graphic: Graphic) => {
|
|
||||||
graphic.file_url = locals.pb.files.getURL(graphic, graphic.file);
|
|
||||||
});
|
|
||||||
|
|
||||||
return graphics;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
results: await fetch_raceresults(),
|
results: await fetch_raceresults(),
|
||||||
races: await fetch_races(),
|
|
||||||
drivers: await fetch_drivers(),
|
|
||||||
graphics: await fetch_graphics(),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -12,28 +12,30 @@
|
|||||||
data_value_name: "race",
|
data_value_name: "race",
|
||||||
label: "Step",
|
label: "Step",
|
||||||
valuefun: async (value: string): Promise<string> =>
|
valuefun: async (value: string): Promise<string> =>
|
||||||
`<span class='badge variant-filled-surface'>${get_by_value(data.races, "id", value)?.step}</span>`,
|
`<span class='badge variant-filled-surface'>${get_by_value(await data.races, "id", value)?.step}</span>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data_value_name: "race",
|
data_value_name: "race",
|
||||||
label: "Race",
|
label: "Race",
|
||||||
valuefun: async (value: string): Promise<string> =>
|
valuefun: async (value: string): Promise<string> =>
|
||||||
`<span>${get_by_value(data.races, "id", value)?.name}</span>`,
|
`<span>${get_by_value(await data.races, "id", value)?.name}</span>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data_value_name: "race",
|
data_value_name: "race",
|
||||||
label: "Guessed",
|
label: "Guessed",
|
||||||
valuefun: async (value: string): Promise<string> =>
|
valuefun: async (value: string): Promise<string> =>
|
||||||
`<span>P${get_by_value(data.races, "id", value)?.pxx}</span>`,
|
`<span>P${get_by_value(await data.races, "id", value)?.pxx}</span>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data_value_name: "pxxs",
|
data_value_name: "pxxs",
|
||||||
label: "Standing",
|
label: "Standing",
|
||||||
valuefun: async (value: string): Promise<string> => {
|
valuefun: async (value: string): Promise<string> => {
|
||||||
const pxxs_array: string[] = value.toString().split(",");
|
const pxxs_array: string[] = value.toString().split(",");
|
||||||
const pxxs_codes: string[] = pxxs_array.map(
|
const pxxs_codes: string[] = await Promise.all(
|
||||||
(id: string, index: number) =>
|
pxxs_array.map(
|
||||||
`<span class='w-10 badge mr-2 text-center' style='background: ${PXX_COLORS[index]};'>${get_by_value(data.drivers, "id", id)?.code ?? "Invalid"}</span>`,
|
async (id: string, index: number) =>
|
||||||
|
`<span class='w-10 badge mr-2 text-center' style='background: ${PXX_COLORS[index]};'>${get_by_value(await data.drivers, "id", id)?.code ?? "Invalid"}</span>`,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return pxxs_codes.join("");
|
return pxxs_codes.join("");
|
||||||
@ -46,9 +48,11 @@
|
|||||||
if (value.length === 0 || value === "") return "";
|
if (value.length === 0 || value === "") return "";
|
||||||
|
|
||||||
const dnfs_array: string[] = value.toString().split(",");
|
const dnfs_array: string[] = value.toString().split(",");
|
||||||
const dnfs_codes: string[] = dnfs_array.map(
|
const dnfs_codes: string[] = await Promise.all(
|
||||||
(id: string) =>
|
dnfs_array.map(
|
||||||
`<span class='w-10 text-center badge mr-2' style='background: ${PXX_COLORS[3]}'>${get_by_value(data.drivers, "id", id)?.code ?? "Invalid"}</span>`,
|
async (id: string) =>
|
||||||
|
`<span class='w-10 text-center badge mr-2' style='background: ${PXX_COLORS[3]}'>${get_by_value(await data.drivers, "id", id)?.code ?? "Invalid"}</span>`,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return dnfs_codes.join("");
|
return dnfs_codes.join("");
|
||||||
@ -64,8 +68,8 @@
|
|||||||
component: "raceResultCard",
|
component: "raceResultCard",
|
||||||
meta: {
|
meta: {
|
||||||
disable_inputs: !data.admin,
|
disable_inputs: !data.admin,
|
||||||
drivers: data.drivers,
|
drivers: await data.drivers,
|
||||||
races: data.races,
|
races: await data.races,
|
||||||
result: get_by_value(data.results, "id", id),
|
result: get_by_value(data.results, "id", id),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -73,14 +77,14 @@
|
|||||||
modalStore.trigger(modalSettings);
|
modalStore.trigger(modalSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
const create_result_handler = (event: Event) => {
|
const create_result_handler = async (event: Event) => {
|
||||||
const modalSettings: ModalSettings = {
|
const modalSettings: ModalSettings = {
|
||||||
type: "component",
|
type: "component",
|
||||||
component: "raceResultCard",
|
component: "raceResultCard",
|
||||||
meta: {
|
meta: {
|
||||||
disable_inputs: !data.admin,
|
disable_inputs: !data.admin,
|
||||||
drivers: data.drivers,
|
drivers: await data.drivers,
|
||||||
races: data.races,
|
races: await data.races,
|
||||||
require_inputs: true,
|
require_inputs: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
import type { Team, Driver, Race, Substitution, Graphic } from "$lib/schema";
|
|
||||||
import type { LayoutServerLoad } from "./$types";
|
|
||||||
|
|
||||||
// This "load" function runs serverside only, as it's located inside +layout.server.ts
|
|
||||||
export const load: LayoutServerLoad = async ({ fetch, locals }) => {
|
|
||||||
// TODO: Duplicated code from racepicks/+page.server.ts + users/+page.server.ts
|
|
||||||
const fetch_graphics = async (): Promise<Graphic[]> => {
|
|
||||||
const graphics: Graphic[] = await locals.pb
|
|
||||||
.collection("graphics")
|
|
||||||
.getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
graphics.map((graphic: Graphic) => {
|
|
||||||
graphic.file_url = locals.pb.files.getURL(graphic, graphic.file);
|
|
||||||
});
|
|
||||||
|
|
||||||
return graphics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_teams = async (): Promise<Team[]> => {
|
|
||||||
const teams: Team[] = await locals.pb.collection("teams").getFullList({
|
|
||||||
sort: "+name",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
teams.map((team: Team) => {
|
|
||||||
team.banner_url = locals.pb.files.getURL(team, team.banner);
|
|
||||||
team.logo_url = locals.pb.files.getURL(team, team.logo);
|
|
||||||
});
|
|
||||||
|
|
||||||
return teams;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Duplicated code from racepicks/+page.server.ts and data/raceresults/+page.server.ts
|
|
||||||
const fetch_drivers = async (): Promise<Driver[]> => {
|
|
||||||
const drivers: Driver[] = await locals.pb.collection("drivers").getFullList({
|
|
||||||
sort: "+code",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
drivers.map((driver: Driver) => {
|
|
||||||
driver.headshot_url = locals.pb.files.getURL(driver, driver.headshot);
|
|
||||||
});
|
|
||||||
|
|
||||||
return drivers;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Duplicated code from racepicks/+page.server.ts and data/raceresults/+page.server.ts
|
|
||||||
const fetch_races = async (): Promise<Race[]> => {
|
|
||||||
const races: Race[] = await locals.pb.collection("races").getFullList({
|
|
||||||
sort: "+step",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
races.map((race: Race) => {
|
|
||||||
race.pictogram_url = locals.pb.files.getURL(race, race.pictogram);
|
|
||||||
});
|
|
||||||
|
|
||||||
return races;
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetch_substitutions = async (): Promise<Substitution[]> => {
|
|
||||||
const substitutions: Substitution[] = await locals.pb.collection("substitutions").getFullList({
|
|
||||||
expand: "race",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort by race step (ascending)
|
|
||||||
substitutions.sort((a, b) => a.expand.race.step - b.expand.race.step);
|
|
||||||
|
|
||||||
return substitutions;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Graphics and teams are awaited, since those are visible on page load.
|
|
||||||
graphics: await fetch_graphics(),
|
|
||||||
teams: await fetch_teams(),
|
|
||||||
|
|
||||||
// The rest is streamed gradually, since the user has to switch pages to need them.
|
|
||||||
drivers: fetch_drivers(),
|
|
||||||
races: fetch_races(),
|
|
||||||
substitutions: fetch_substitutions(),
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, type TableColumn, Table } from "$lib/components";
|
import { Button, type TableColumn, Table } from "$lib/components";
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value, get_driver_headshot_template } from "$lib/database";
|
||||||
import type { Driver, Team } from "$lib/schema";
|
import type { Driver, Team } from "$lib/schema";
|
||||||
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
@ -31,7 +31,7 @@
|
|||||||
data_value_name: "team",
|
data_value_name: "team",
|
||||||
label: "Team",
|
label: "Team",
|
||||||
valuefun: async (value: string): Promise<string> => {
|
valuefun: async (value: string): Promise<string> => {
|
||||||
const team: Team | undefined = get_by_value(data.teams, "id", value);
|
const team: Team | undefined = get_by_value(await data.teams, "id", value);
|
||||||
return team
|
return team
|
||||||
? `<span class='badge border mr-2' style='color: ${team.color}; background: ${team.color};'>C</span>${team.name}`
|
? `<span class='badge border mr-2' style='color: ${team.color}; background: ${team.color};'>C</span>${team.name}`
|
||||||
: "<span class='badge variant-filled-primary'>Invalid</span>";
|
: "<span class='badge variant-filled-primary'>Invalid</span>";
|
||||||
@ -57,7 +57,7 @@
|
|||||||
component: "driverCard",
|
component: "driverCard",
|
||||||
meta: {
|
meta: {
|
||||||
driver: driver,
|
driver: driver,
|
||||||
teams: data.teams,
|
teams: await data.teams,
|
||||||
team_select_value: update_driver_team_select_values[driver.id],
|
team_select_value: update_driver_team_select_values[driver.id],
|
||||||
active_value: update_driver_active_values[driver.id],
|
active_value: update_driver_active_values[driver.id],
|
||||||
disable_inputs: !data.admin,
|
disable_inputs: !data.admin,
|
||||||
@ -72,13 +72,12 @@
|
|||||||
type: "component",
|
type: "component",
|
||||||
component: "driverCard",
|
component: "driverCard",
|
||||||
meta: {
|
meta: {
|
||||||
teams: data.teams,
|
teams: await data.teams,
|
||||||
team_select_value: update_driver_team_select_values["create"],
|
team_select_value: update_driver_team_select_values["create"],
|
||||||
active_value: update_driver_active_values["create"],
|
active_value: update_driver_active_values["create"],
|
||||||
disable_inputs: !data.admin,
|
disable_inputs: !data.admin,
|
||||||
require_inputs: true,
|
require_inputs: true,
|
||||||
headshot_template:
|
headshot_template: get_driver_headshot_template(await data.graphics),
|
||||||
get_by_value(data.graphics, "name", "driver_headshot_template")?.file_url ?? "Invalid",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { Button, Table, type TableColumn } from "$lib/components";
|
import { Button, Table, type TableColumn } from "$lib/components";
|
||||||
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value, get_race_pictogram_template } from "$lib/database";
|
||||||
import type { Race } from "$lib/schema";
|
import type { Race } from "$lib/schema";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
@ -62,8 +62,7 @@
|
|||||||
meta: {
|
meta: {
|
||||||
disable_inputs: !data.admin,
|
disable_inputs: !data.admin,
|
||||||
require_inputs: true,
|
require_inputs: true,
|
||||||
pictogram_template:
|
pictogram_template: get_race_pictogram_template(await data.graphics),
|
||||||
get_by_value(data.graphics, "name", "race_pictogram_template")?.file_url ?? "Invalid",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value, get_driver_headshot_template } from "$lib/database";
|
||||||
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
import type { Race, Substitution } from "$lib/schema";
|
import type { Race, Substitution } from "$lib/schema";
|
||||||
import { Button, Table, type DropdownOption, type TableColumn } from "$lib/components";
|
import { Button, Table, type TableColumn } from "$lib/components";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
|
// TODO: Cleanup
|
||||||
const update_substitution_substitute_select_values: { [key: string]: string } = $state({});
|
const update_substitution_substitute_select_values: { [key: string]: string } = $state({});
|
||||||
const update_substitution_for_select_values: { [key: string]: string } = $state({});
|
const update_substitution_for_select_values: { [key: string]: string } = $state({});
|
||||||
const update_substitution_race_select_values: { [key: string]: string } = $state({});
|
const update_substitution_race_select_values: { [key: string]: string } = $state({});
|
||||||
@ -85,8 +86,7 @@
|
|||||||
disable_inputs: !data.admin,
|
disable_inputs: !data.admin,
|
||||||
race_select_value: update_substitution_race_select_values["create"],
|
race_select_value: update_substitution_race_select_values["create"],
|
||||||
require_inputs: true,
|
require_inputs: true,
|
||||||
headshot_template:
|
headshot_template: get_driver_headshot_template(await data.graphics),
|
||||||
get_by_value(data.graphics, "name", "driver_headshot_template")?.file_url ?? "Invalid",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import type { Team } from "$lib/schema";
|
import type { Team } from "$lib/schema";
|
||||||
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
import { getModalStore, type ModalSettings, type ModalStore } from "@skeletonlabs/skeleton";
|
||||||
import type { PageData } from "./$types";
|
import type { PageData } from "./$types";
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value, get_team_banner_template, get_team_logo_template } from "$lib/database";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
@ -25,7 +25,7 @@
|
|||||||
const modalStore: ModalStore = getModalStore();
|
const modalStore: ModalStore = getModalStore();
|
||||||
|
|
||||||
const teams_handler = async (event: Event, id: string) => {
|
const teams_handler = async (event: Event, id: string) => {
|
||||||
const team: Team | undefined = get_by_value(data.teams, "id", id);
|
const team: Team | undefined = get_by_value(await data.teams, "id", id);
|
||||||
if (!team) return;
|
if (!team) return;
|
||||||
|
|
||||||
const modalSettings: ModalSettings = {
|
const modalSettings: ModalSettings = {
|
||||||
@ -40,15 +40,13 @@
|
|||||||
modalStore.trigger(modalSettings);
|
modalStore.trigger(modalSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
const create_team_handler = (event: Event) => {
|
const create_team_handler = async (event: Event) => {
|
||||||
const modalSettings: ModalSettings = {
|
const modalSettings: ModalSettings = {
|
||||||
type: "component",
|
type: "component",
|
||||||
component: "teamCard",
|
component: "teamCard",
|
||||||
meta: {
|
meta: {
|
||||||
banner_template:
|
banner_template: get_team_banner_template(await data.graphics),
|
||||||
get_by_value(data.graphics, "name", "team_banner_template")?.file_url ?? "Invalid",
|
logo_template: get_team_logo_template(await data.graphics),
|
||||||
logo_template:
|
|
||||||
get_by_value(data.graphics, "name", "team_logo_template")?.file_url ?? "Invalid",
|
|
||||||
require_inputs: true,
|
require_inputs: true,
|
||||||
disable_inputs: !data.admin,
|
disable_inputs: !data.admin,
|
||||||
},
|
},
|
||||||
@ -63,4 +61,6 @@
|
|||||||
<span class="font-bold">Create New Team</span>
|
<span class="font-bold">Create New Team</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Table data={data.teams} columns={teams_columns} handler={teams_handler} />
|
{#await data.teams then teams}
|
||||||
|
<Table data={teams} columns={teams_columns} handler={teams_handler} />
|
||||||
|
{/await}
|
||||||
|
@ -14,21 +14,7 @@ export const load: PageServerLoad = async ({ fetch, locals }) => {
|
|||||||
return users;
|
return users;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Duplicated code from data/season/+layout.server.ts + racepicks/+page.server.ts
|
|
||||||
const fetch_graphics = async (): Promise<Graphic[]> => {
|
|
||||||
const graphics: Graphic[] = await locals.pb
|
|
||||||
.collection("graphics")
|
|
||||||
.getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
graphics.map((graphic: Graphic) => {
|
|
||||||
graphic.file_url = locals.pb.files.getURL(graphic, graphic.file);
|
|
||||||
});
|
|
||||||
|
|
||||||
return graphics;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
users: await fetch_users(),
|
users: await fetch_users(),
|
||||||
graphics: await fetch_graphics(),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
data_value_name: "avatar_url",
|
data_value_name: "avatar_url",
|
||||||
label: "Avatar",
|
label: "Avatar",
|
||||||
valuefun: async (value: string): Promise<string> =>
|
valuefun: async (value: string): Promise<string> =>
|
||||||
`<img class='rounded-full w-10 bg-surface-400' src='${value ? value : get_by_value(data.graphics, "name", "driver_headshot_template")?.file_url}'/>`,
|
`<img class='rounded-full w-10 bg-surface-400' src='${value ? value : get_by_value(await data.graphics, "name", "driver_headshot_template")?.file_url}'/>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data_value_name: "admin",
|
data_value_name: "admin",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { form_data_clean, form_data_ensure_keys, form_data_get_and_remove_id } from "$lib/form";
|
import { form_data_clean, form_data_ensure_keys, form_data_get_and_remove_id } from "$lib/form";
|
||||||
import type { CurrentPickedUser, Driver, Graphic, Race, RacePick, RaceResult } from "$lib/schema";
|
import type { CurrentPickedUser, Race, RacePick, RaceResult } from "$lib/schema";
|
||||||
import type { Actions, PageServerLoad } from "./$types";
|
import type { Actions, PageServerLoad } from "./$types";
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ fetch, locals }) => {
|
export const load: PageServerLoad = async ({ fetch, locals }) => {
|
||||||
@ -53,55 +53,11 @@ export const load: PageServerLoad = async ({ fetch, locals }) => {
|
|||||||
return raceresults;
|
return raceresults;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Duplicated code from data/season/+layout.server.ts and data/raceresults/+page.server.ts
|
|
||||||
const fetch_drivers = async (): Promise<Driver[]> => {
|
|
||||||
const drivers: Driver[] = await locals.pb.collection("drivers").getFullList({
|
|
||||||
sort: "+code",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
drivers.map((driver: Driver) => {
|
|
||||||
driver.headshot_url = locals.pb.files.getURL(driver, driver.headshot);
|
|
||||||
});
|
|
||||||
|
|
||||||
return drivers;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Duplicated code from data/season/+layout.server.ts and data/raceresults/+page.server.ts
|
|
||||||
const fetch_races = async (): Promise<Race[]> => {
|
|
||||||
const races: Race[] = await locals.pb.collection("races").getFullList({
|
|
||||||
sort: "+step",
|
|
||||||
fetch: fetch,
|
|
||||||
});
|
|
||||||
|
|
||||||
races.map((race: Race) => {
|
|
||||||
race.pictogram_url = locals.pb.files.getURL(race, race.pictogram);
|
|
||||||
});
|
|
||||||
|
|
||||||
return races;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Duplicated code from data/season/+layout.server.ts + users/+page.server.ts
|
|
||||||
const fetch_graphics = async (): Promise<Graphic[]> => {
|
|
||||||
const graphics: Graphic[] = await locals.pb
|
|
||||||
.collection("graphics")
|
|
||||||
.getFullList({ fetch: fetch });
|
|
||||||
|
|
||||||
graphics.map((graphic: Graphic) => {
|
|
||||||
graphic.file_url = locals.pb.files.getURL(graphic, graphic.file);
|
|
||||||
});
|
|
||||||
|
|
||||||
return graphics;
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
racepicks: await fetch_racepicks(),
|
racepicks: await fetch_racepicks(),
|
||||||
currentrace: await fetch_currentrace(),
|
currentrace: await fetch_currentrace(),
|
||||||
currentpickedusers: await fetch_currentpickedusers(),
|
currentpickedusers: await fetch_currentpickedusers(),
|
||||||
raceresults: await fetch_raceresults(),
|
raceresults: await fetch_raceresults(),
|
||||||
drivers: await fetch_drivers(),
|
|
||||||
races: await fetch_races(),
|
|
||||||
graphics: await fetch_graphics(),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
RACE_PICTOGRAM_HEIGHT,
|
RACE_PICTOGRAM_HEIGHT,
|
||||||
RACE_PICTOGRAM_WIDTH,
|
RACE_PICTOGRAM_WIDTH,
|
||||||
} from "$lib/config";
|
} from "$lib/config";
|
||||||
import type { CurrentPickedUser, Driver, Race, RacePick } from "$lib/schema";
|
import type { CurrentPickedUser, RacePick } from "$lib/schema";
|
||||||
import { get_by_value } from "$lib/database";
|
import { get_by_value, get_driver_headshot_template } from "$lib/database";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
|
||||||
let { data }: { data: PageData } = $props();
|
let { data }: { data: PageData } = $props();
|
||||||
@ -44,10 +44,9 @@
|
|||||||
racepick: currentpick,
|
racepick: currentpick,
|
||||||
currentrace: data.currentrace,
|
currentrace: data.currentrace,
|
||||||
user: data.user,
|
user: data.user,
|
||||||
drivers: data.drivers,
|
drivers: await data.drivers,
|
||||||
disable_inputs: false, // TODO: Datelock
|
disable_inputs: false, // TODO: Datelock
|
||||||
headshot_template:
|
headshot_template: get_driver_headshot_template(await data.graphics),
|
||||||
get_by_value(data.graphics, "name", "driver_headshot_template")?.file_url ?? "Invalid",
|
|
||||||
pxx_select_value: pxx_select_value,
|
pxx_select_value: pxx_select_value,
|
||||||
dnf_select_value: dnf_select_value,
|
dnf_select_value: dnf_select_value,
|
||||||
},
|
},
|
||||||
@ -56,13 +55,9 @@
|
|||||||
modalStore.trigger(modalSettings);
|
modalStore.trigger(modalSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getrace = (id: string): Race | undefined => get_by_value(data.races, "id", id);
|
|
||||||
const getdriver = (id: string): Driver | undefined => get_by_value(data.drivers, "id", id);
|
|
||||||
|
|
||||||
const pickedusers = data.currentpickedusers.filter(
|
const pickedusers = data.currentpickedusers.filter(
|
||||||
(currentpickeduser: CurrentPickedUser) => currentpickeduser.picked,
|
(currentpickeduser: CurrentPickedUser) => currentpickeduser.picked,
|
||||||
);
|
);
|
||||||
// pickedusers = pickedusers.concat(pickedusers, pickedusers);
|
|
||||||
const outstandingusers = data.currentpickedusers.filter(
|
const outstandingusers = data.currentpickedusers.filter(
|
||||||
(currentpickeduser: CurrentPickedUser) => !currentpickeduser.picked,
|
(currentpickeduser: CurrentPickedUser) => !currentpickeduser.picked,
|
||||||
);
|
);
|
||||||
@ -70,9 +65,6 @@
|
|||||||
const dateformat: string = "dd.MM' 'HH:mm";
|
const dateformat: string = "dd.MM' 'HH:mm";
|
||||||
const formatdate = (date: string): string => format(new Date(date), dateformat);
|
const formatdate = (date: string): string => format(new Date(date), dateformat);
|
||||||
|
|
||||||
const graphicfallback = (graphic: string | undefined, fallback: string): string =>
|
|
||||||
graphic ?? get_by_value(data.graphics, "name", fallback)?.file_url ?? "Invalid";
|
|
||||||
|
|
||||||
const race_popupsettings = (target: string): PopupSettings => {
|
const race_popupsettings = (target: string): PopupSettings => {
|
||||||
return {
|
return {
|
||||||
event: "click",
|
event: "click",
|
||||||
@ -139,33 +131,37 @@
|
|||||||
<div class="mt-2 flex gap-2">
|
<div class="mt-2 flex gap-2">
|
||||||
<div class="card w-full p-2 pb-0 shadow">
|
<div class="card w-full p-2 pb-0 shadow">
|
||||||
<h1 class="mb-2 text-nowrap font-bold">Your P{data.currentrace.pxx} Pick:</h1>
|
<h1 class="mb-2 text-nowrap font-bold">Your P{data.currentrace.pxx} Pick:</h1>
|
||||||
<LazyImage
|
{#await data.graphics then graphics}
|
||||||
src={graphicfallback(
|
{#await data.drivers then drivers}
|
||||||
getdriver(currentpick?.pxx ?? "")?.headshot_url,
|
<LazyImage
|
||||||
"driver_headshot_template",
|
src={get_by_value(drivers, "id", currentpick?.pxx ?? "")?.headshot_url ??
|
||||||
)}
|
get_driver_headshot_template(graphics)}
|
||||||
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
||||||
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
||||||
containerstyle="height: 115px; margin: auto;"
|
containerstyle="height: 115px; margin: auto;"
|
||||||
imgclass="bg-transparent cursor-pointer"
|
imgclass="bg-transparent cursor-pointer"
|
||||||
hoverzoom
|
hoverzoom
|
||||||
onclick={create_guess_handler}
|
onclick={create_guess_handler}
|
||||||
/>
|
/>
|
||||||
|
{/await}
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
<div class="card w-full p-2 pb-0 shadow">
|
<div class="card w-full p-2 pb-0 shadow">
|
||||||
<h1 class="mb-2 text-nowrap font-bold">Your DNF Pick:</h1>
|
<h1 class="mb-2 text-nowrap font-bold">Your DNF Pick:</h1>
|
||||||
<LazyImage
|
{#await data.graphics then graphics}
|
||||||
src={graphicfallback(
|
{#await data.drivers then drivers}
|
||||||
getdriver(currentpick?.dnf ?? "")?.headshot_url,
|
<LazyImage
|
||||||
"driver_headshot_template",
|
src={get_by_value(drivers, "id", currentpick?.dnf ?? "")?.headshot_url ??
|
||||||
)}
|
get_driver_headshot_template(graphics)}
|
||||||
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
imgwidth={DRIVER_HEADSHOT_WIDTH}
|
||||||
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
imgheight={DRIVER_HEADSHOT_HEIGHT}
|
||||||
containerstyle="height: 115px; margin: auto;"
|
containerstyle="height: 115px; margin: auto;"
|
||||||
imgclass="bg-transparent cursor-pointer"
|
imgclass="bg-transparent cursor-pointer"
|
||||||
hoverzoom
|
hoverzoom
|
||||||
onclick={create_guess_handler}
|
onclick={create_guess_handler}
|
||||||
/>
|
/>
|
||||||
|
{/await}
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@ -177,15 +173,17 @@
|
|||||||
Picked ({pickedusers.length}/{data.currentpickedusers.length}):
|
Picked ({pickedusers.length}/{data.currentpickedusers.length}):
|
||||||
</h1>
|
</h1>
|
||||||
<div class="mt-1 grid grid-cols-4 gap-x-2 gap-y-0.5">
|
<div class="mt-1 grid grid-cols-4 gap-x-2 gap-y-0.5">
|
||||||
{#each pickedusers.slice(0, 16) as user}
|
{#await data.graphics then graphics}
|
||||||
<LazyImage
|
{#each pickedusers.slice(0, 16) as user}
|
||||||
src={graphicfallback(user.avatar_url, "driver_headshot_template")}
|
<LazyImage
|
||||||
imgwidth={AVATAR_WIDTH}
|
src={user.avatar_url ?? get_driver_headshot_template(graphics)}
|
||||||
imgheight={AVATAR_HEIGHT}
|
imgwidth={AVATAR_WIDTH}
|
||||||
containerstyle="height: 35px; width: 35px;"
|
imgheight={AVATAR_HEIGHT}
|
||||||
imgclass="bg-surface-400 rounded-full"
|
containerstyle="height: 35px; width: 35px;"
|
||||||
/>
|
imgclass="bg-surface-400 rounded-full"
|
||||||
{/each}
|
/>
|
||||||
|
{/each}
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card w-full p-2 shadow">
|
<div class="card w-full p-2 shadow">
|
||||||
@ -193,15 +191,17 @@
|
|||||||
Outstanding ({outstandingusers.length}/{data.currentpickedusers.length}):
|
Outstanding ({outstandingusers.length}/{data.currentpickedusers.length}):
|
||||||
</h1>
|
</h1>
|
||||||
<div class="mt-1 grid grid-cols-4 gap-x-0 gap-y-0.5">
|
<div class="mt-1 grid grid-cols-4 gap-x-0 gap-y-0.5">
|
||||||
{#each outstandingusers.slice(0, 16) as user}
|
{#await data.graphics then graphics}
|
||||||
<LazyImage
|
{#each outstandingusers.slice(0, 16) as user}
|
||||||
src={graphicfallback(user.avatar_url, "driver_headshot_template")}
|
<LazyImage
|
||||||
imgwidth={AVATAR_WIDTH}
|
src={user.avatar_url ?? get_driver_headshot_template(graphics)}
|
||||||
imgheight={AVATAR_HEIGHT}
|
imgwidth={AVATAR_WIDTH}
|
||||||
containerstyle="height: 35px; width: 35px;"
|
imgheight={AVATAR_HEIGHT}
|
||||||
imgclass="bg-surface-400 rounded-full"
|
containerstyle="height: 35px; width: 35px;"
|
||||||
/>
|
imgclass="bg-surface-400 rounded-full"
|
||||||
{/each}
|
/>
|
||||||
|
{/each}
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -216,7 +216,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<!-- Points color coding legend -->
|
<!-- Points color coding legend -->
|
||||||
<!-- Use mt-3/mt-4 to account for 2x padding around the avatar. -->
|
<!-- Use mt-3/mt-4 to account for 2x padding around the avatar. -->
|
||||||
<div class="mt-4 h-10">
|
<div class="mt-4 h-10 w-7 lg:w-36">
|
||||||
<div class="hidden h-5 text-sm font-bold lg:block">Points:</div>
|
<div class="hidden h-5 text-sm font-bold lg:block">Points:</div>
|
||||||
<div
|
<div
|
||||||
class="flex h-full flex-col overflow-hidden rounded-b-lg rounded-t-lg shadow lg:h-5 lg:flex-row lg:!rounded-l-lg lg:!rounded-r-lg lg:rounded-b-none lg:rounded-t-none"
|
class="flex h-full flex-col overflow-hidden rounded-b-lg rounded-t-lg shadow lg:h-5 lg:flex-row lg:!rounded-l-lg lg:!rounded-r-lg lg:rounded-b-none lg:rounded-t-none"
|
||||||
@ -255,53 +255,57 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#each data.raceresults as result}
|
{#await data.races then races}
|
||||||
{@const race = getrace(result.race)}
|
{#each data.raceresults as result}
|
||||||
|
{@const race = get_by_value(races, "id", result.race)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
use:popup={race_popupsettings(race?.id ?? "Invalid")}
|
use:popup={race_popupsettings(race?.id ?? "Invalid")}
|
||||||
class="card mt-2 flex h-20 w-7 flex-col !rounded-r-none bg-surface-300 p-2 shadow lg:w-36"
|
class="card mt-2 flex h-20 w-7 flex-col !rounded-r-none bg-surface-300 p-2 shadow lg:w-36"
|
||||||
>
|
>
|
||||||
<span class="hidden text-sm font-bold lg:block">
|
<span class="hidden text-sm font-bold lg:block">
|
||||||
{race?.step}: {race?.name}
|
{race?.step}: {race?.name}
|
||||||
</span>
|
</span>
|
||||||
<span class="block rotate-90 text-sm font-bold lg:hidden">
|
<span class="block rotate-90 text-sm font-bold lg:hidden">
|
||||||
{race?.name.slice(0, 8)}{(race?.name.length ?? 8) > 8 ? "." : ""}
|
{race?.name.slice(0, 8)}{(race?.name.length ?? 8) > 8 ? "." : ""}
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden text-sm lg:block">Date: {formatdate(race?.racedate ?? "")}</span>
|
<span class="hidden text-sm lg:block">Date: {formatdate(race?.racedate ?? "")}</span>
|
||||||
<span class="hidden text-sm lg:block">Guessed: P{race?.pxx}</span>
|
<span class="hidden text-sm lg:block">Guessed: P{race?.pxx}</span>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- The race result popup is triggered on click on the race -->
|
|
||||||
<div data-popup={race?.id ?? "Invalid"} class="card z-10 p-2 shadow">
|
|
||||||
<span class="font-bold">Result:</span>
|
|
||||||
<div class="mt-2 flex flex-col gap-1">
|
|
||||||
{#each result.pxxs as pxx, index}
|
|
||||||
{@const driver = getdriver(pxx)}
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<span class="w-8">P{(race?.pxx ?? -100) - 3 + index}:</span>
|
|
||||||
<span class="badge w-10 p-1 text-center" style="background: {PXX_COLORS[index]};">
|
|
||||||
{driver?.code}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
|
|
||||||
{#if result.dnfs.length > 0}
|
|
||||||
<hr class="border-black" style="border-style: inset;" />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#each result.dnfs as dnf}
|
|
||||||
{@const driver = getdriver(dnf)}
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<span class="w-8">DNF:</span>
|
|
||||||
<span class="badge w-10 p-1 text-center" style="background: {PXX_COLORS[3]};">
|
|
||||||
{driver?.code}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{/each}
|
<!-- The race result popup is triggered on click on the race -->
|
||||||
|
<div data-popup={race?.id ?? "Invalid"} class="card z-10 p-2 shadow">
|
||||||
|
<span class="font-bold">Result:</span>
|
||||||
|
<div class="mt-2 flex flex-col gap-1">
|
||||||
|
{#await data.drivers then drivers}
|
||||||
|
{#each result.pxxs as pxx, index}
|
||||||
|
{@const driver = get_by_value(drivers, "id", pxx)}
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<span class="w-8">P{(race?.pxx ?? -100) - 3 + index}:</span>
|
||||||
|
<span class="badge w-10 p-1 text-center" style="background: {PXX_COLORS[index]};">
|
||||||
|
{driver?.code}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#if result.dnfs.length > 0}
|
||||||
|
<hr class="border-black" style="border-style: inset;" />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#each result.dnfs as dnf}
|
||||||
|
{@const driver = get_by_value(drivers, "id", dnf)}
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<span class="w-8">DNF:</span>
|
||||||
|
<span class="badge w-10 p-1 text-center" style="background: {PXX_COLORS[3]};">
|
||||||
|
{driver?.code}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/await}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hide-scrollbar flex w-full overflow-x-scroll pb-2">
|
<div class="hide-scrollbar flex w-full overflow-x-scroll pb-2">
|
||||||
@ -317,13 +321,15 @@
|
|||||||
>
|
>
|
||||||
<!-- Avatar + name display at the top -->
|
<!-- Avatar + name display at the top -->
|
||||||
<div class="mx-auto flex h-10 w-fit">
|
<div class="mx-auto flex h-10 w-fit">
|
||||||
<LazyImage
|
{#await data.graphics then graphics}
|
||||||
src={graphicfallback(user.avatar_url, "driver_headshot_template")}
|
<LazyImage
|
||||||
imgwidth={AVATAR_WIDTH}
|
src={user.avatar_url ?? get_driver_headshot_template(graphics)}
|
||||||
imgheight={AVATAR_HEIGHT}
|
imgwidth={AVATAR_WIDTH}
|
||||||
containerstyle="height: 40px; width: 40px;"
|
imgheight={AVATAR_HEIGHT}
|
||||||
imgclass="bg-surface-400 rounded-full"
|
containerstyle="height: 40px; width: 40px;"
|
||||||
/>
|
imgclass="bg-surface-400 rounded-full"
|
||||||
|
/>
|
||||||
|
{/await}
|
||||||
<div
|
<div
|
||||||
style="height: 40px; line-height: 40px;"
|
style="height: 40px; line-height: 40px;"
|
||||||
class="ml-2 hidden text-nowrap text-center align-middle lg:block"
|
class="ml-2 hidden text-nowrap text-center align-middle lg:block"
|
||||||
@ -332,34 +338,38 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#each data.raceresults as result}
|
{#await data.races then races}
|
||||||
{@const race = getrace(result.race)}
|
{#await data.drivers then drivers}
|
||||||
{@const pick = picks.filter((pick: RacePick) => pick.race === race?.id)[0]}
|
{#each data.raceresults as result}
|
||||||
{@const pxxcolor = PXX_COLORS[result.pxxs.indexOf(pick?.pxx ?? "Invalid")]}
|
{@const race = get_by_value(races, "id", result.race)}
|
||||||
{@const dnfcolor =
|
{@const pick = picks.filter((pick: RacePick) => pick.race === race?.id)[0]}
|
||||||
result.dnfs.indexOf(pick?.dnf ?? "Invalid") >= 0 ? PXX_COLORS[3] : PXX_COLORS[-1]}
|
{@const pxxcolor = PXX_COLORS[result.pxxs.indexOf(pick?.pxx ?? "Invalid")]}
|
||||||
|
{@const dnfcolor =
|
||||||
|
result.dnfs.indexOf(pick?.dnf ?? "Invalid") >= 0 ? PXX_COLORS[3] : PXX_COLORS[-1]}
|
||||||
|
|
||||||
{#if pick}
|
{#if pick}
|
||||||
<div class="mt-2 h-20 w-full border bg-surface-300 p-1 lg:p-2">
|
<div class="mt-2 h-20 w-full border bg-surface-300 p-1 lg:p-2">
|
||||||
<div class="mx-auto flex h-full w-fit flex-col justify-evenly">
|
<div class="mx-auto flex h-full w-fit flex-col justify-evenly">
|
||||||
<span
|
<span
|
||||||
class="p-1 text-center text-sm rounded-container-token"
|
class="p-1 text-center text-sm rounded-container-token"
|
||||||
style="background: {pxxcolor};"
|
style="background: {pxxcolor};"
|
||||||
>
|
>
|
||||||
{getdriver(pick?.pxx ?? "")?.code}
|
{get_by_value(drivers, "id", pick?.pxx ?? "")?.code}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
class="p-1 text-center text-sm rounded-container-token"
|
class="p-1 text-center text-sm rounded-container-token"
|
||||||
style="background: {dnfcolor};"
|
style="background: {dnfcolor};"
|
||||||
>
|
>
|
||||||
{getdriver(pick?.dnf ?? "")?.code}
|
{get_by_value(drivers, "id", pick?.dnf ?? "")?.code}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="mt-2 h-20 w-full"></div>
|
<div class="mt-2 h-20 w-full"></div>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
{/await}
|
||||||
|
{/await}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user