feat: tool banners

This commit is contained in:
TrèsAbhi committed 2026-01-14 13:30:12 -06:00
1 parent 1a18058228
commit a7f93698a6
10 files changed
+161 -6

No files matched your search

@@ -0,0 +1,3 @@
<svg width="30" height="52" viewBox="0 0 30 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.8564 44V52H0V36L13.8564 44ZM30 52H16.1436V44L30 36V52ZM28.8564 18V34L15 42L1.14355 34V18L15 10L28.8564 18ZM13.8564 8L0 16V0H13.8564V8ZM30 16L16.1436 8V0H30V16Z" fill="#EEEEF0"/>
</svg>

After

Width:  |  Height:  |  Size: 294 B

@@ -12,7 +12,7 @@
background-size: cover;
background-position: center;
box-shadow: var(--shadow-interactive), var(--shadow-subtle);
box-shadow: var(--shadow-interactive), var(--shadow-aggressive);
}
.avatar-label {
@@ -24,6 +24,13 @@ import "@fontsource-variable/roboto-flex";
--font-size-minor: 0.75rem;
--font-size-major: 1.25rem;
--font-size-heading-1: 3rem;
--font-size-heading-2: 2rem;
--font-size-heading-3: 1.5rem;
--font-size-heading-4: 1.25rem;
--font-size-heading-5: 1rem;
--font-size-heading-6: 0.75rem;
--font-family-regular: "Roboto Flex Variable", sans-serif;
--font-family-mono: "JetBrains Mono Variable", monospace;
@@ -64,9 +71,11 @@ import "@fontsource-variable/roboto-flex";
var(--shadow-interactive-shine), var(--shadow-interactive-shadow),
var(--shadow-interactive-background);
--shadow-subtle: var(--space-1) var(--space-1) var(--space-4)
--shadow-aggressive: var(--space-1) var(--space-1) var(--space-4)
var(--black-a11);
--shadow-subtle: 0 var(--space-1) var(--space-3) var(--black-a5);
--blur-glass: blur(4rem);
--blur-tint: blur(16rem);
}
</style>
@@ -0,0 +1,25 @@
.heading {
&[data-size="1"] {
font-size: var(--font-size-heading-1);
}
&[data-size="2"] {
font-size: var(--font-size-heading-2);
}
&[data-size="3"] {
font-size: var(--font-size-heading-3);
}
&[data-size="4"] {
font-size: var(--font-size-heading-4);
}
&[data-size="5"] {
font-size: var(--font-size-heading-5);
}
&[data-size="6"] {
font-size: var(--font-size-heading-6);
}
}
@@ -0,0 +1,23 @@
import { classNames } from "../../core/ui/classNames";
import { Text, type TextProps } from "../Text";
import "./index.css";
export interface HeadingProps extends Omit<TextProps, "size"> {
size?: `${1 | 2 | 3 | 4 | 5 | 6}`;
}
export function Heading({
className,
weight,
size = "1",
...props
}: HeadingProps) {
return (
<Text
{...props}
weight={weight ?? "medium"}
className={classNames("heading", className)}
data-size={size}
/>
);
}
@@ -20,8 +20,8 @@ const { locale } = Astro.props;
justify-content: center;
z-index: 1;
backdrop-filter: var(--blur-glass);
background-color: var(--black-a5);
backdrop-filter: var(--blur-glass) brightness(25%);
box-shadow: var(--shadow-subtle);
.content {
flex: 1;
@@ -0,0 +1,81 @@
---
import { api } from "../core/api/dynamic";
import type { Tool } from "../core/tools/tools";
import { Heading } from "./Heading";
import { Text } from "./Text";
interface Props {
locale: string;
tool: Tool;
}
const { tool, locale } = Astro.props;
const strings = await api.strings(locale);
const toolStrings = strings.tools[tool.id as keyof typeof strings.tools];
---
<style>
.tool-hero {
background-size: cover;
.content {
width: 100%;
height: 100%;
position: relative;
display: flex;
justify-content: center;
padding: var(--space-5) var(--space-4);
box-sizing: border-box;
backdrop-filter: var(--blur-tint);
.centered {
flex: 1;
max-width: var(--page-width);
display: flex;
flex-direction: column;
}
.pattern {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url(/assets/patterns/avatars.svg);
mask-image: linear-gradient(
90deg,
transparent 25%,
var(--black-a1),
transparent
);
mask-repeat: no-repeat;
mask-size: cover;
}
}
}
</style>
<div
class="tool-hero"
style={{
backgroundImage: `url(/assets/tools/${tool.id}.webp)`,
backgroundPosition: tool.background_position ?? "top",
}}
>
<div class="content">
<div class="pattern"></div>
<div class="centered">
<Heading weight="medium" size="2">
{toolStrings.name}
</Heading>
<Text>
{toolStrings.slogan}
</Text>
</div>
</div>
</div>
@@ -8,6 +8,8 @@ export interface Tool {
significant?: boolean;
disabled?: boolean;
href?: string;
background_position: "top" | "center" | "bottom";
}
export const tools: Record<string, Tool> = {
@@ -16,11 +18,15 @@ export const tools: Record<string, Tool> = {
strings: "tankopedia",
button: "purple",
significant: true,
background_position: "top",
},
avatars: {
id: "avatars",
button: "gold",
background_position: "bottom",
},
backgrounds: {
@@ -16,12 +16,14 @@ interface Props {
const { accent, noNavbar, locale } = Astro.props;
---
<html>
<html lang={locale}>
<head>
<BaseMeta />
<ColorScale color="mauve" />
<ColorScale color="mauve" alpha />
<ColorAlias color="mauve" alias="gray" />
<ColorAlias color="mauve" alpha alias="gray" />
<ColorScale color="black" alpha />
<ColorScale color="white" alpha />
@@ -36,7 +38,6 @@ const { accent, noNavbar, locale } = Astro.props;
display: flex;
flex-direction: column;
min-height: 100dvh;
gap: var(--space-4);
background-color: var(--gray-1);
color: var(--gray-12);
@@ -47,6 +48,7 @@ const { accent, noNavbar, locale } = Astro.props;
flex: 1;
flex-direction: column;
gap: var(--space-5);
padding: var(--space-4) 0;
}
}
</style>
@@ -57,6 +59,8 @@ const { accent, noNavbar, locale } = Astro.props;
<body class="dark">
{!noNavbar && <Navbar {locale} />}
<slot name="pre-app" />
<div class="app">
<slot />
</div>
@@ -1,5 +1,7 @@
---
import Section from "../../../components/Section.astro";
import ToolBanner from "../../../components/ToolBanner.astro";
import { tools } from "../../../core/tools/tools";
import BaseLayout from "../../../layouts/BaseLayout.astro";
import { Page } from "./_index";
@@ -17,6 +19,8 @@ const { locale } = Astro.props;
</style>
<BaseLayout {locale} accent="gold">
<ToolBanner {locale} tool={tools.avatars} slot="pre-app" />
<Section>
<Page {locale} client:only="react">
<Page {locale} skeleton slot="fallback" />