mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-11-01 23:10:37 +01:00
Compare commits
4
Commits
d42fc0e3f6
...
6f47f5cc99
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f47f5cc99 | ||
|
|
1117dcb935 | ||
|
|
01a58f9aa8 | ||
|
|
9096644d51 |
No files matched your search
@@ -20,10 +20,26 @@
|
||||
},
|
||||
|
||||
"tools": {
|
||||
"tanks": { "name": "Tankopedia" },
|
||||
"avatars": { "name": "Avatars" },
|
||||
"backgrounds": { "name": "Backgrounds" },
|
||||
"api": { "name": "API" }
|
||||
"tanks": {
|
||||
"name": "Tankopedia",
|
||||
"slogan": "Blitz tank encyclopedia",
|
||||
"action": "Find tanks"
|
||||
},
|
||||
"avatars": {
|
||||
"name": "Avatars",
|
||||
"slogan": "Blitz player avatars",
|
||||
"action": "Browse all"
|
||||
},
|
||||
"backgrounds": {
|
||||
"name": "Backgrounds",
|
||||
"slogan": "Blitz player backgrounds",
|
||||
"action": "View all"
|
||||
},
|
||||
"api": {
|
||||
"name": "API",
|
||||
"action": "To docs",
|
||||
"slogan": "BlitzKit hosted API"
|
||||
}
|
||||
},
|
||||
|
||||
"home": {
|
||||
|
||||
File renamed without changes.
|
Before Width: | Height: | Size: 676 KiB After Width: | Height: | Size: 676 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 405 KiB |
@@ -4,7 +4,7 @@ import "@fontsource-variable/roboto-flex";
|
||||
---
|
||||
|
||||
<style>
|
||||
body {
|
||||
:root {
|
||||
--space-0: 0.0625rem;
|
||||
--space-1: 0.125rem;
|
||||
--space-2: 0.25rem;
|
||||
@@ -18,39 +18,30 @@ import "@fontsource-variable/roboto-flex";
|
||||
|
||||
--max-size: max(100vw, 100vh);
|
||||
|
||||
--font-size-regular: var(--space-4);
|
||||
--font-size-regular: 1rem;
|
||||
--font-size-minor: 0.75rem;
|
||||
|
||||
--font-family-regular: "Roboto Flex Variable", sans-serif;
|
||||
--font-family-mono: "JetBrains Mono Variable", monospace;
|
||||
|
||||
--weight-thin: 100;
|
||||
--weight-extra-light: 200;
|
||||
--weight-light: 300;
|
||||
--weight-regular: 400;
|
||||
--weight-medium: 500;
|
||||
--weight-semibold: 600;
|
||||
--weight-bold: 700;
|
||||
--weight-extra-bold: 800;
|
||||
--weight-black: 900;
|
||||
|
||||
--outline-interactive: solid var(--space-1) var(--gray-5);
|
||||
--outline-focus: var(--space-1) solid var(--accent-6);
|
||||
|
||||
--shadow-cavity:
|
||||
inset var(--space-1) var(--space-1) var(--space-1) var(--gray-2),
|
||||
inset calc(var(--space-1) * -1) calc(var(--space-1) * -1) var(--space-1)
|
||||
var(--gray-4);
|
||||
--shadow-focus: 0 0 var(--space-3) var(--accent-4);
|
||||
|
||||
background-color: var(--gray-1);
|
||||
color: var(--gray-12);
|
||||
font-family: var(--font-family-regular);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
inset calc(var(--space-1) * sin(45deg)) calc(var(--space-1) * sin(45deg))
|
||||
var(--space-1) var(--black-a3),
|
||||
inset calc(var(--space-1) * sin(45deg) * -1)
|
||||
calc(var(--space-1) * sin(45deg) * -1) var(--space-1) var(--white-a1);
|
||||
--shadow-bump:
|
||||
inset calc(var(--space-1) * sin(45deg)) calc(var(--space-1) * sin(45deg))
|
||||
var(--space-1) var(--white-a3),
|
||||
inset calc(var(--space-1) * sin(45deg) * -1)
|
||||
calc(var(--space-1) * sin(45deg) * -1) var(--space-1) var(--black-a3);
|
||||
}
|
||||
</style>
|
||||
@@ -1,2 +1,25 @@
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
border-radius: var(--max-size);
|
||||
padding: var(--space-3) var(--space-4);
|
||||
|
||||
background-color: var(--accent-9);
|
||||
border: none;
|
||||
|
||||
font-family: var(--font-family-regular);
|
||||
font-size: var(--font-size-minor);
|
||||
color: var(--gray-1);
|
||||
font-weight: var(--weight-medium);
|
||||
|
||||
.svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
&[data-light-text="true"] {
|
||||
color: var(--gray-12);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,39 @@
|
||||
import type { ComponentProps } from "react";
|
||||
import { classNames } from "../../core/ui/classNames";
|
||||
import type { Color } from "../../core/ui/color";
|
||||
import "./index.css";
|
||||
|
||||
export interface ButtonProps extends ComponentProps<"button"> {}
|
||||
export interface ButtonProps extends ComponentProps<"button"> {
|
||||
color?: Color;
|
||||
variant?: "solid";
|
||||
}
|
||||
|
||||
export function Button({ className, ...props }: ButtonProps) {
|
||||
return <button className={classNames("button", className)} {...props} />;
|
||||
const LIGHT_TEXT_COLORS = new Set<Color>([
|
||||
"purple",
|
||||
"gold",
|
||||
"bronze",
|
||||
"teal",
|
||||
"grass",
|
||||
]);
|
||||
|
||||
export function Button({
|
||||
className,
|
||||
color,
|
||||
variant = "solid",
|
||||
style,
|
||||
...props
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<button
|
||||
className={classNames("button", className)}
|
||||
data-color={color}
|
||||
data-variant={variant}
|
||||
data-light-text={color ? LIGHT_TEXT_COLORS.has(color) : undefined}
|
||||
style={{
|
||||
backgroundColor: color ? `var(--${color}-9)` : undefined,
|
||||
...style,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -3,11 +3,18 @@ import * as colors from "@radix-ui/colors";
|
||||
import type { Color } from "../core/ui/color";
|
||||
|
||||
interface Props {
|
||||
color: Color;
|
||||
color: Color | AlphaOnlyColor;
|
||||
alpha?: boolean;
|
||||
}
|
||||
|
||||
const { color } = Astro.props;
|
||||
const scale = colors[`${color}Dark`];
|
||||
const ALPHA_ONLY_COLORS = ["black", "white"] as const;
|
||||
type AlphaOnlyColor = (typeof ALPHA_ONLY_COLORS)[number];
|
||||
|
||||
const { color, alpha } = Astro.props;
|
||||
const name = `${color}${
|
||||
ALPHA_ONLY_COLORS.includes(color as AlphaOnlyColor) ? "" : "Dark"
|
||||
}${alpha ? "A" : ""}`;
|
||||
const scale = colors[name as keyof typeof colors];
|
||||
|
||||
let styles = "";
|
||||
|
||||
@@ -15,8 +22,8 @@ styles += ":root{";
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const n = i + 1;
|
||||
const value = scale[`${color}${n}` as keyof typeof scale];
|
||||
styles += `--${color}-${n}:${value};`;
|
||||
const value = scale[`${color}${alpha ? "A" : ""}${n}` as keyof typeof scale];
|
||||
styles += `--${color}-${alpha ? "a" : ""}${n}:${value};`;
|
||||
}
|
||||
|
||||
styles += "}";
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<style>
|
||||
.footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
padding: var(--space-6) var(--space-4);
|
||||
|
||||
background-color: var(--gray-3);
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
max-width: 52rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="footer">
|
||||
<div class="content">poopy</div>
|
||||
</div>
|
||||
@@ -0,0 +1,14 @@
|
||||
.link {
|
||||
color: var(--accent-11);
|
||||
text-decoration-color: currentColor;
|
||||
|
||||
&[data-underline="hover"],
|
||||
&[data-underline="never"] {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&[data-underline="hover"]:hover,
|
||||
&[data-underline="hover"]:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { ComponentProps } from "react";
|
||||
import { classNames } from "../../core/ui/classNames";
|
||||
import "./index.css";
|
||||
|
||||
export interface LinkProps extends ComponentProps<"a"> {
|
||||
underline?: "always" | "hover" | "never";
|
||||
}
|
||||
|
||||
export function Link({ className, underline = "always", ...props }: LinkProps) {
|
||||
return (
|
||||
<a
|
||||
className={classNames("link", className)}
|
||||
{...props}
|
||||
data-underline={underline}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import { Link, type LinkProps } from "./Link";
|
||||
|
||||
export interface LinkI18n extends LinkProps {
|
||||
locale: string;
|
||||
}
|
||||
|
||||
export function LinkI18n({ locale, href, ...props }: LinkI18n) {
|
||||
return (
|
||||
<Link
|
||||
href={`${locale === locales.default ? "" : `/${locale}`}${href}`}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<style>
|
||||
.section {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0 var(--space-4);
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
max-width: 52rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="section">
|
||||
<div class="content">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,3 +1,27 @@
|
||||
.text {
|
||||
font-size: var(--font-size-regular);
|
||||
|
||||
&[data-size="minor"] {
|
||||
font-size: var(--font-size-minor);
|
||||
}
|
||||
|
||||
&[data-weight="light"] {
|
||||
font-weight: var(--weight-light);
|
||||
}
|
||||
|
||||
&[data-weight="regular"] {
|
||||
font-weight: var(--weight-regular);
|
||||
}
|
||||
|
||||
&[data-weight="medium"] {
|
||||
font-weight: var(--weight-medium);
|
||||
}
|
||||
|
||||
&[data-weight="bold"] {
|
||||
font-weight: var(--weight-bold);
|
||||
}
|
||||
|
||||
&[data-weight="black"] {
|
||||
font-weight: var(--weight-black);
|
||||
}
|
||||
}
|
||||
@@ -5,19 +5,26 @@ import "./index.css";
|
||||
|
||||
export interface TextProps extends ComponentProps<"span"> {
|
||||
color?: Color;
|
||||
weight?: "light" | "regular" | "medium" | "bold" | "black";
|
||||
lowContrast?: boolean;
|
||||
size?: "regular" | "minor";
|
||||
}
|
||||
|
||||
export function Text({
|
||||
color = "gray",
|
||||
lowContrast,
|
||||
className,
|
||||
size = "regular",
|
||||
weight,
|
||||
style,
|
||||
...props
|
||||
}: TextProps) {
|
||||
return (
|
||||
<span
|
||||
className={classNames("text", className)}
|
||||
style={{ color: `var(--${color}-${lowContrast ? 11 : 12})` }}
|
||||
style={{ color: `var(--${color}-${lowContrast ? 11 : 12})`, ...style }}
|
||||
data-size={size}
|
||||
data-weight={weight}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
.text-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
gap: var(--space-3);
|
||||
margin: 0 var(--space-4);
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import type { ComponentProps, ReactNode } from "react";
|
||||
import {
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
type ComponentProps,
|
||||
type ReactNode,
|
||||
} from "react";
|
||||
import { classNames } from "../../core/ui/classNames";
|
||||
import "./index.css";
|
||||
|
||||
@@ -6,14 +12,20 @@ export interface TextFieldProps extends ComponentProps<"input"> {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export function TextField({ children, className, ...props }: TextFieldProps) {
|
||||
return (
|
||||
<div
|
||||
className={classNames("text-field", className)}
|
||||
data-has-icon={children !== undefined}
|
||||
>
|
||||
{children}
|
||||
<input {...props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
({ children, className, ...props }, ref) => {
|
||||
const input = useRef<HTMLInputElement>(null);
|
||||
|
||||
useImperativeHandle(ref, () => input.current!, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames("text-field", className)}
|
||||
data-has-icon={children !== undefined}
|
||||
>
|
||||
{children}
|
||||
<input ref={input} {...props} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -1,31 +1,95 @@
|
||||
---
|
||||
import { CaretRightIcon } from "@radix-ui/react-icons";
|
||||
import type { Tool } from "../core/tools/tools";
|
||||
import { api } from "../core/api/dynamic";
|
||||
import { type Tool } from "../core/tools/tools";
|
||||
import { Button } from "./Button";
|
||||
import { LinkI18n } from "./LinkI18n";
|
||||
import { Text } from "./Text";
|
||||
|
||||
interface Props {
|
||||
tool: Tool;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const { tool } = Astro.props;
|
||||
const { tool, locale } = Astro.props;
|
||||
const strings = await api.strings(locale);
|
||||
const toolStrings = strings.tools[tool.id as keyof typeof strings.tools];
|
||||
---
|
||||
|
||||
<style>
|
||||
.tool-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 10rem;
|
||||
position: relative;
|
||||
|
||||
border-radius: var(--space-3);
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
overflow: hidden;
|
||||
|
||||
.poster {
|
||||
flex: 1;
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-4);
|
||||
|
||||
backdrop-filter: blur(var(--space-6));
|
||||
|
||||
.readable {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.shadow {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border-radius: var(--space-3);
|
||||
box-shadow: var(--shadow-bump);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="tool-card">
|
||||
<div>
|
||||
<div>
|
||||
<Text>{tool.id}</Text>
|
||||
<Text>{tool.id}</Text>
|
||||
<LinkI18n
|
||||
{locale}
|
||||
href={`/${tool.id}`}
|
||||
className="tool-card"
|
||||
underline="never"
|
||||
style={{
|
||||
backgroundImage: `url(/assets/tools/${tool.id}.webp)`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="poster"
|
||||
style={{
|
||||
backgroundImage: `url(/assets/tools/${tool.id}.webp)`,
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
<div class="readable">
|
||||
<Text weight="medium">{toolStrings.name}</Text>
|
||||
<Text size="minor" lowContrast>{toolStrings.slogan}</Text>
|
||||
</div>
|
||||
|
||||
<Button>
|
||||
{tool.id}
|
||||
<Button color={tool.button}>
|
||||
{toolStrings.action}
|
||||
<CaretRightIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shadow"></div>
|
||||
</LinkI18n>
|
||||
@@ -25,12 +25,12 @@ export const tools: Record<string, Tool> = {
|
||||
|
||||
backgrounds: {
|
||||
id: "backgrounds",
|
||||
button: "amber",
|
||||
button: "gold",
|
||||
},
|
||||
|
||||
api: {
|
||||
id: "api",
|
||||
disabled: true,
|
||||
button: "bronze",
|
||||
button: "lime",
|
||||
},
|
||||
};
|
||||
@@ -3,8 +3,9 @@ import BaseMeta from "../components/BaseMeta.astro";
|
||||
import BaseStyles from "../components/BaseStyles.astro";
|
||||
import ColorAlias from "../components/ColorAlias.astro";
|
||||
import ColorScale from "../components/ColorScale.astro";
|
||||
import Footer from "../components/Footer.astro";
|
||||
import Navbar from "../components/Navbar.astro";
|
||||
import type { Color } from "../pages/styles/colors/[accent].css";
|
||||
import type { Color } from "../core/ui/color";
|
||||
|
||||
interface Props {
|
||||
accent: Color;
|
||||
@@ -23,10 +24,28 @@ const { accent, noNavbar } = Astro.props;
|
||||
<ColorAlias color="mauve" alias="gray" />
|
||||
<ColorAlias color={accent} alias="accent" />
|
||||
<BaseStyles />
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-5);
|
||||
|
||||
background-color: var(--gray-1);
|
||||
color: var(--gray-12);
|
||||
font-family: var(--font-family-regular);
|
||||
}
|
||||
</style>
|
||||
|
||||
<slot name="head" />
|
||||
</head>
|
||||
|
||||
<body class="dark">
|
||||
{!noNavbar && <Navbar />}
|
||||
|
||||
<slot />
|
||||
|
||||
{(<Footer />)}
|
||||
</body>
|
||||
</html>
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
} from "typescript";
|
||||
import BaseLayout from "../../../layouts/BaseLayout.astro";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
const root = `/src/pages/api`;
|
||||
const globbed = import.meta.glob("/src/pages/api/**/*.ts", {
|
||||
eager: true,
|
||||
|
||||
@@ -4,6 +4,8 @@ import { Grade } from "@protos/blitz_static_standard_grades_enum";
|
||||
import { api } from "../../../core/api/dynamic";
|
||||
import BaseLayout from "../../../layouts/BaseLayout.astro";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
const avatars = await api.avatars();
|
||||
---
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import { Grade } from "@protos/blitz_static_standard_grades_enum";
|
||||
import { api } from "../../../core/api/dynamic";
|
||||
import BaseLayout from "../../../layouts/BaseLayout.astro";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
const backgrounds = await api.backgrounds();
|
||||
---
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
import locales from "@blitzkit/i18n/locales.json";
|
||||
import "@radix-ui/colors/amber-dark.css";
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import packageJson from "../../../../../package.json";
|
||||
import ColorScale from "../../components/ColorScale.astro";
|
||||
import HomeHero from "../../components/HomeHero.astro";
|
||||
import Section from "../../components/Section.astro";
|
||||
import ToolCard from "../../components/ToolCard.astro";
|
||||
import { tools } from "../../core/tools/tools";
|
||||
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||
@@ -21,9 +22,15 @@ const { locale } = Astro.props;
|
||||
---
|
||||
|
||||
<BaseLayout accent="amber">
|
||||
<ColorScale color="purple" slot="head" />
|
||||
<ColorScale color="gold" slot="head" />
|
||||
<ColorScale color="lime" slot="head" />
|
||||
<ColorScale color="black" alpha slot="head" />
|
||||
<ColorScale color="white" alpha slot="head" />
|
||||
|
||||
<HomeHero {locale} />
|
||||
|
||||
<h1>blitzkit {packageJson.version}</h1>
|
||||
|
||||
{Object.values(tools).map((tool) => <ToolCard {tool} />)}
|
||||
<Section>
|
||||
{Object.values(tools).map((tool) => <ToolCard {locale} {tool} />)}
|
||||
</Section>
|
||||
</BaseLayout>
|
||||
@@ -3,6 +3,8 @@ import "@radix-ui/colors/violet-dark.css";
|
||||
import { api } from "../../../core/api/dynamic";
|
||||
import BaseLayout from "../../../layouts/BaseLayout.astro";
|
||||
|
||||
export { getStaticPaths } from "../index.astro";
|
||||
|
||||
const tankList = await api.tankList();
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user