Skip to content

Commit e62b3e7

Browse files
Merge pull request #61 from stormgateworld/refactore-layout
New Layout Components
2 parents c69d561 + 7c55ea9 commit e62b3e7

24 files changed

+526
-176
lines changed

src/components/Widget.astro

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
---
2+
import { styles } from "../lib/theme"
3+
24
export interface Props {
35
title?: string
46
label?: string
@@ -7,12 +9,12 @@ export interface Props {
79
const { title, label } = Astro.props
810
---
911

10-
<div class="relative overflow-auto rounded-lg border border-gray-800/80 bg-gray-800/30 p-3 backdrop-blur-md sm:p-4">
12+
<div class:list={[styles.box.base, "relative overflow-auto p-3 sm:p-4"]}>
1113
<div class="sticky left-0 top-0 flex flex-wrap items-center gap-x-5 gap-y-1">
12-
<h3 class="font-display flex-auto text-lg font-bold text-gray-200">
14+
<h3 class="font-display flex-auto text-base font-bold text-gray-300">
1315
{title}
1416
</h3>
15-
<p class="text-md font-bold text-gray-400">
17+
<p class="text-sm font-bold text-gray-500">
1618
{label}
1719
</p>
1820
</div>

src/components/layout/Box.astro

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
---
4+
5+
<div class:list={[styles.box.base, "min-h-52"]}>
6+
<slot />
7+
</div>

src/components/Footer.astro src/components/layout/Footer.astro

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import Svg from "@jasikpark/astro-svg-loader"
33
---
44

5-
<footer class="mt-8 border-t border-white/10 p-4 md:p-6">
5+
<footer class="mt-4 border-t border-gray-900 py-32 text-center md:mt-8">
66
<div class="mx-auto">
77
<nav class="flex columns-2 flex-wrap justify-center gap-x-8 gap-y-2 pb-6 sm:space-x-12" aria-label="Footer">
88
<a href="/api" class="text-sm leading-6 text-gray-100 hover:text-white">API</a>
@@ -32,7 +32,7 @@ import Svg from "@jasikpark/astro-svg-loader"
3232
<div class="flex flex-auto justify-center whitespace-nowrap text-gray-600 lg:flex-none lg:justify-end">
3333
<span>Made by</span>
3434
<a href="https://casuals.co" class="text-gray-500 hover:text-gray-300" target="_blank" rel="noopener">
35-
<Svg src={import("../assets/thecasuals.svg?raw")} class="-mt-1 ml-1 inline-block h-4 fill-current" />
35+
<Svg src={import("../../assets/thecasuals.svg?raw")} class="-mt-1 ml-1 inline-block h-4 fill-current" />
3636
</a>
3737
</div>
3838
</div>

src/components/layout/Header.astro

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
import type { ImageMetadata } from "astro"
3+
import { getImage } from "astro:assets"
4+
import HeaderContent from "./HeaderContent.astro"
5+
6+
interface Props {
7+
backdropImage?: string | ImageMetadata | null
8+
title?: string
9+
section?: string
10+
}
11+
12+
const { backdropImage, section, title } = Astro.props
13+
const isUrl = typeof backdropImage === "string"
14+
const imageUrl = backdropImage ? (isUrl ? backdropImage : (await getImage(backdropImage)).src) : null
15+
---
16+
17+
<div
18+
class="relative -mt-20 border-b border-white/5 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-900 pt-20 [--tw-gradient-via-position:40%] md:-mt-16 md:pt-16"
19+
>
20+
{
21+
backdropImage && (
22+
<div class="absolute inset-0 overflow-hidden">
23+
<div
24+
class="h-full w-full bg-cover bg-center opacity-40 mix-blend-lighten blur-3xl brightness-50 saturate-150"
25+
style={`background-image: url(${imageUrl})`}
26+
/>
27+
</div>
28+
)
29+
}
30+
{(section || title) && <HeaderContent section={section} title={title} />}
31+
<slot />
32+
</div>
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
4+
interface Props {
5+
section?: string
6+
title?: string
7+
}
8+
9+
const { title, section } = Astro.props
10+
---
11+
12+
<div class:list={[styles.layout.container, styles.layout.containerPadding, "relative"]}>
13+
<div class="flex items-center py-4">
14+
{
15+
Astro.slots.has("left") && (
16+
<div>
17+
<slot name="left" />
18+
</div>
19+
)
20+
}
21+
<div class="flex-auto py-4">
22+
{section && <p class="text-base font-bold text-white/60">{section}</p>}
23+
{title && <h1 class="text-xl font-black text-white/90 md:text-3xl">{title}</h1>}
24+
<slot />
25+
</div>
26+
{
27+
Astro.slots.has("right") && (
28+
<div>
29+
<slot name="right" />
30+
</div>
31+
)
32+
}
33+
</div>
34+
</div>
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
4+
type MetaItem = { label: string; icon?: Promise<typeof import("*.svg?raw")> }
5+
interface Props {
6+
items?: MetaItem[]
7+
}
8+
9+
const items = await Promise.all(
10+
Astro.props.items
11+
? Astro.props.items.map(async (item) => {
12+
return {
13+
...item,
14+
icon: item.icon ? (await item.icon)?.default : undefined,
15+
}
16+
})
17+
: []
18+
)
19+
---
20+
21+
<div class="bg-black/20">
22+
<div
23+
class:list={[
24+
styles.layout.container,
25+
styles.layout.containerPadding,
26+
"flex flex-wrap items-center gap-y-4 gap-4 md:gap-8 py-4 mix-blend-lighten",
27+
]}
28+
>
29+
{
30+
items?.map(({ label, icon }) => (
31+
<div class="flex items-center gap-2">
32+
{icon && <span class="text-white opacity-20 *:h-4 *:w-4 md:*:h-5 md:*:w-5" set:html={icon} />}
33+
<span class="text-xs font-bold text-white/30 md:text-sm">{label}</span>
34+
</div>
35+
))
36+
}
37+
</div>
38+
</div>

src/components/layout/HeaderNav.astro

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
const currentRoute = new URL(Astro.request.url).pathname
4+
type Link = {
5+
label: string
6+
href?: string
7+
}
8+
9+
interface Props {
10+
/** The breadcrumb up to but excluding current page */
11+
breadcrumb?: Link[]
12+
/** The current page or current and sibling pages/tabs */
13+
current: Link | Link[]
14+
}
15+
const { breadcrumb, current } = Astro.props
16+
const tabs = Array.isArray(current) ? current : [current]
17+
---
18+
19+
<div class="scrollbar-hide overflow-x-auto border-b border-white/7 bg-white/3">
20+
<div
21+
class:list={[
22+
styles.layout.container,
23+
styles.layout.containerPadding,
24+
"flex items-center gap-y-4 gap-4 sm:gap-8 py-2 font-extrabold text-xs md:text-sm whitespace-nowrap",
25+
]}
26+
>
27+
{
28+
breadcrumb?.map(({ label, href }) => (
29+
<>
30+
<a href={href} class:list={["text-white/50", tabs.length > 1 && "hidden sm:inline"]}>
31+
{label}
32+
</a>
33+
<span class:list={["text-white/35 w-2 -mx-2 text-center", tabs.length > 1 && "hidden sm:inline"]}>/</span>
34+
</>
35+
))
36+
}
37+
{
38+
tabs.map(({ label, href }) => (
39+
<>
40+
<a
41+
href={href}
42+
class:list={[
43+
"text-xs md:text-sm font-bold",
44+
href == currentRoute ? "text-white/90" : "text-white/50 hover:text-white/100",
45+
]}
46+
>
47+
{label}
48+
</a>
49+
</>
50+
))
51+
}
52+
</div>
53+
</div>

src/components/layout/Main.astro

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
---
4+
5+
<div class:list={["basis-3/4 flex flex-col", styles.layout.gap]}>
6+
<slot />
7+
</div>

src/components/layout/MainNav.astro

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
const currentRoute = new URL(Astro.request.url).pathname
4+
const navLinks = [
5+
{ href: "/leaderboards/ranked_1v1", text: "Leaderboard" },
6+
{ href: "/stats", text: "Stats" },
7+
{ href: "/social", text: "Content" },
8+
{ href: "/api", text: "API" },
9+
{ href: "/tools", text: "Tools" },
10+
// { href: "/creators", text: "Creators" },
11+
]
12+
---
13+
14+
<div
15+
class="to-black-20 sticky top-0 z-10 h-20 w-full border-b border-white/5 bg-gradient-to-r from-black/40 via-black/25 mix-blend-screen backdrop-blur md:h-16"
16+
>
17+
<nav
18+
class:list={[
19+
styles.layout.container,
20+
"flex flex-wrap md:flex-nowrap items-center gap-y-2 py-2 md:min-h-16 md:py-4",
21+
]}
22+
>
23+
<a
24+
href="/"
25+
class:list={[
26+
styles.layout.containerPadding,
27+
"basis-full whitespace-nowrap md:pr-2 text-xl font-extrabold text-white/90 md:basis-auto ",
28+
]}
29+
>
30+
Stormgate World
31+
</a>
32+
33+
<div
34+
class:list={[
35+
styles.layout.containerPadding,
36+
"scrollbar-hide -ml-2 flex max-w-full flex-auto gap-1 gap-y-2 overflow-x-auto md:ml-0 md:gap-4 md:pr-7",
37+
]}
38+
>
39+
{
40+
navLinks.map(({ href, text }) => (
41+
<a
42+
href={href}
43+
class:list={[
44+
"font-extrabold rounded px-2 text-sm md:text-base md:px-3 py-1 md:py-1.5",
45+
currentRoute === href ? "bg-white/5 text-white/80" : "hover:bg-white/5 text-white/60 ",
46+
]}
47+
>
48+
{text}
49+
</a>
50+
))
51+
}
52+
53+
<div class="flex-auto"></div>
54+
<div>{/*search etc */}</div>
55+
</div>
56+
</nav>
57+
</div>

src/components/layout/Section.astro

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
4+
interface Props {
5+
title?: string
6+
description?: string
7+
class?: string
8+
}
9+
const { title, description, class: classes } = Astro.props
10+
const hasHeader = title || description || Astro.slots.header || Astro.slots.controls
11+
---
12+
13+
<div class:list={[styles.layout.container, styles.layout.containerPadding, "pt-4 md:pt-6", classes]}>
14+
{
15+
hasHeader && (
16+
<div class="my-4 flex justify-between gap-4 md:my-6">
17+
<div class="flex-auto">
18+
{title && <h2 class="text-2xl font-bold text-white">{title}</h2>}
19+
{description && <p class="text-gray-400">{description}</p>}
20+
<slot name="header" />
21+
</div>
22+
<div class="flex-none">
23+
<slot name="controls" />
24+
</div>
25+
</div>
26+
)
27+
}
28+
<div class:list={["flex flex-col lg:flex-row", styles.layout.gap]}>
29+
<slot />
30+
</div>
31+
</div>

src/components/layout/Sidebar.astro

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
import { styles } from "../../lib/theme"
3+
---
4+
5+
<div
6+
class:list={["flex md:grid grid-cols-2 only:*:[grid-column:span_2] basis-1/4 lg:flex flex-col", styles.layout.gap]}
7+
>
8+
<slot />
9+
</div>

src/components/widgets/GameLengthChart.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// @ts-nocheck
2-
32
import { onMount } from "solid-js"
43
import { Chart, Colors, Title, Tooltip, type ChartOptions, type ChartData } from "chart.js"
54
import { Bar } from "solid-chartjs"
@@ -38,12 +37,12 @@ export function GameLengthChart(props: GameLengthProps) {
3837
{
3938
label: "Wins",
4039
data: wins,
41-
backgroundColor: "#5EC269",
40+
backgroundColor: "#4CA154",
4241
},
4342
{
4443
label: "Losses",
4544
data: losses,
46-
backgroundColor: "#DD524C",
45+
backgroundColor: "#CA3A31",
4746
},
4847
],
4948
}

src/components/widgets/MatchPreview.astro

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const mainPlayer = match.players.find((player) => player.player?.player_id === m
1818
<div
1919
class:list={[
2020
"size-6 text-sm ml-1 flex justify-center items-center rounded text-gray-800 font-extrabold uppercase",
21-
mainPlayer.result === "win" ? "bg-green-500" : mainPlayer.result === "loss" ? "bg-red-500" : "bg-gray-500",
21+
mainPlayer.result === "win" ? "bg-green-600" : mainPlayer.result === "loss" ? "bg-red-600" : "bg-gray-500",
2222
]}
2323
>
2424
{mainPlayer.result === "win" ? "W" : mainPlayer.result === "loss" ? "L" : "-"}
@@ -33,7 +33,7 @@ const mainPlayer = match.players.find((player) => player.player?.player_id === m
3333
<span
3434
class:list={[
3535
"w-8 flex-none text-xs whitespace-nowrap text-right",
36-
player.mmr_diff! > 0 ? "text-green-500" : player.mmr_diff! < 0 ? "text-red-500" : "text-gray-500",
36+
player.mmr_diff! > 0 ? "text-green-600" : player.mmr_diff! < 0 ? "text-red-600" : "text-gray-500",
3737
]}
3838
>
3939
{player.mmr_diff! > 0 ? "" : ""}

src/components/widgets/PlayerActivity.astro

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import type { PlayerActivityStats, PlayerResponse } from "../../lib/api"
33
import Widget from "../Widget.astro"
44
import { Tooltip } from "../ui/Tooltip"
55
6+
const WEEKS_DISPLAYED = 15
7+
68
interface Props {
79
player: PlayerResponse
810
activity: PlayerActivityStats
@@ -33,9 +35,13 @@ type Day = { date: Date; win_rate: number; games_count: number; size: number; to
3335
type Week = Day[]
3436
const today = new Date()
3537
// get the date of monday 12 weeks ago, fully including this week
36-
const start = new Date(today.getFullYear(), today.getMonth(), today.getDate() - today.getDay() - 11 * 7)
38+
const start = new Date(
39+
today.getFullYear(),
40+
today.getMonth(),
41+
today.getDate() - today.getDay() - (WEEKS_DISPLAYED - 1) * 7
42+
)
3743
const weeks: Week[] = []
38-
for (let i = 0; i < 12; i++) {
44+
for (let i = 0; i < WEEKS_DISPLAYED; i++) {
3945
const week: Week = []
4046
for (let j = 0; j < 7; j++) {
4147
const date = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i * 7 + j)

0 commit comments

Comments
 (0)