page-redesign #22

Merged
Chaoscaot merged 9 commits from page-redesign into master 2026-04-23 12:23:27 +02:00
31 changed files with 1028 additions and 372 deletions
Showing only changes of commit d2ee422d6d - Show all commits

View File

@@ -5,5 +5,5 @@ import localBau from "@images/90.png";
<Image src={localBau} alt="Bau" widths={[240, 540, 720, 1080, 1920, localBau.width]}
sizes={`(max-width: 240px) 240px, (max-width: 540px) 540px, (max-width: 720px) 720px, (max-width: 1080px) 1080px, (max-width: 1920px) 1920px, ${localBau.width}px`}
class="w-full h-full object-cover rounded-b-2xl shadow-2xl" quality={100}
class="w-full h-full object-cover" quality={100}
draggable="false" loading="eager"/>

View File

@@ -52,7 +52,7 @@
}
let { hoverEffect = true, extraClasses = "", children }: Props = $props();
let classes = $derived(twMerge("w-72 border-2 border-gray-100 flex flex-col items-center p-8 m-4 rounded-xl shadow-lg bg-zinc-900 dark:border-gray-800 dark:text-gray-100", extraClasses));
let classes = $derived(twMerge("flex flex-col items-center p-8 m-4 bg-[#0c0c0c] border border-[rgba(255,255,255,0.06)] text-gray-100", extraClasses));
</script>
<div class={classes} bind:this={cardElement} onmousemove={rotateElement} onmouseleave={resetElement} class:hoverEffect>
@@ -67,10 +67,13 @@
:global(h1) {
@apply text-xl font-bold mt-4;
font-family: "Barlow Condensed", sans-serif;
letter-spacing: 0.06em;
}
:global(svg) {
@apply transition-transform duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl;
color: #f59e0b;
@apply transition-transform duration-300 ease-in-out hover:scale-110;
}
}

View File

@@ -44,7 +44,7 @@
}
</script>
<div class="p-3 bg-gray-200 dark:bg-neutral-800 rounded-2xl w-3/4 mx-auto">
<div class="p-3 bg-[#0c0c0c] border border-[rgba(255,255,255,0.06)] w-3/4 mx-auto">
<table>
<thead>
<tr class="font-bold border-b">

View File

@@ -44,7 +44,7 @@
);
</script>
<div class="p-3 bg-gray-200 dark:bg-neutral-800 rounded-2xl w-3/4 mx-auto">
<div class="p-3 bg-[#0c0c0c] border border-[rgba(255,255,255,0.06)] w-3/4 mx-auto">
<table class="w-full">
<thead>
<tr class="font-bold border-b">

View File

@@ -2,7 +2,7 @@
import {t} from "astro-i18n";
---
<div class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4" role="alert">
<p class="font-bold">{t("warning.title")}</p>
<p>{t("warning.text")}</p>
<div class="border-l-2 border-amber-500 bg-amber-500/5 p-4" role="alert">
<p class="font-bold text-amber-400" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.1em; text-transform: uppercase;">{t("warning.title")}</p>
<p class="text-gray-400 text-sm">{t("warning.text")}</p>
</div>

View File

@@ -74,8 +74,8 @@
});
</script>
<form class="bg-gray-100 dark:bg-neutral-900 p-12 rounded-2xl shadow-2xl border-2 border-gray-600 flex flex-col" onsubmit={preventDefault(login)}>
<h1 class="text-4xl text-white text-center">{t("login.title")}</h1>
<form class="sw-login-form" onsubmit={preventDefault(login)}>
<h1 class="text-4xl text-white text-center" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.08em;">{t("login.title")}</h1>
<div class="ml-2 flex flex-col">
<label for="username">{t("login.label.username")}</label>
<input type="text" id="username" name="username" placeholder={t("login.placeholder.username")} bind:value={username} />
@@ -83,24 +83,65 @@
<input type="password" id="password" name="password" placeholder={t("login.placeholder.password")} bind:value={pw} />
</div>
<p class="mt-2">
<a class="text-neutral-500 hover:underline" href={l("/set-password")}>{t("login.setPassword")}</a>
<a class="sw-link" href={l("/set-password")}>{t("login.setPassword")}</a>
</p>
{#if error}
<p class="mt-2 text-red-500">{error}</p>
{/if}
<button class="btn mt-4 !mx-0 justify-center" type="submit" onclick={preventDefault(login)}>{t("login.submit")}</button>
<a class="btn mt-4 !mx-0 justify-center" href="https://discord.com/oauth2/authorize?client_id=869606970099904562&response_type=token&redirect_uri=https%3A%2F%2Fsteamwar.de%2Flogin&scope=identify">
<button class="btn mt-4 justify-center w-full" type="submit" onclick={preventDefault(login)}>{t("login.submit")}</button>
<a class="btn mt-4 justify-center w-full" href="https://discord.com/oauth2/authorize?client_id=869606970099904562&response_type=token&redirect_uri=https%3A%2F%2Fsteamwar.de%2Flogin&scope=identify">
{t("login.discord")}
</a>
</form>
<style lang="postcss">
.sw-login-form {
background: rgba(12, 12, 12, 0.95);
border: 1px solid rgba(255, 255, 255, 0.06);
border-top: 2px solid #f59e0b;
backdrop-filter: blur(24px);
padding: 3rem;
display: flex;
flex-direction: column;
}
input {
@apply border-2 rounded-md p-2 shadow-2xl w-80 dark:bg-neutral-800 focus:outline-none focus:ring-2 focus:ring-neutral-500 focus:border-transparent text-black;
width: 20rem;
padding: 0.6rem 0.8rem;
margin-top: 0.25rem;
margin-bottom: 0.5rem;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
color: #f5f5f5;
font-size: 0.85rem;
outline: none;
transition: border-color 0.2s ease;
}
input:focus {
border-color: rgba(245, 158, 11, 0.5);
}
label {
@apply text-neutral-300;
font-family: "Barlow Condensed", sans-serif;
font-size: 0.7rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: rgba(163, 163, 163, 0.7);
margin-top: 0.5rem;
}
.sw-link {
color: rgba(163, 163, 163, 0.5);
text-decoration: none;
font-size: 0.85rem;
border-bottom: 1px solid transparent;
transition: color 0.2s, border-color 0.2s;
}
.sw-link:hover {
color: #f59e0b;
border-bottom-color: #f59e0b;
}
</style>

View File

@@ -49,9 +49,9 @@
function handleScroll() {
if (window.scrollY > 0) {
navbar!.classList.add("before:scale-y-100");
navbar!.classList.add("sw-nav-scrolled");
} else {
navbar!.classList.remove("before:scale-y-100");
navbar!.classList.remove("sw-nav-scrolled");
}
}
</script>
@@ -60,15 +60,15 @@
<nav
data-pagefind-ignore
class="z-20 fixed top-0 left-0 right-0 sm:px-4 py-1 transition-colors flex justify-center before:backdrop-blur before:shadow-2xl before:absolute before:top-0 before:left-0 before:bottom-0 before:right-0 before:-z-10 before:scale-y-0 before:transition-transform before:origin-top"
class="sw-nav z-20 fixed top-0 left-0 right-0 sm:px-4 py-1 transition-colors flex justify-center"
bind:this={navbar}
>
<div class="flex flex-row items-center justify-evenly md:justify-between match">
<a class="flex items-center" href={l("/")}>
{@render logo?.()}
<span class="text-2xl uppercase font-bold text-white hidden md:inline-block">
<span class="sw-nav-title hidden md:inline-block">
{t("navbar.title")}
<span class="before:scale-y-100" style="display: none" aria-hidden="true"></span>
<span class="scrolled-trigger" style="display: none" aria-hidden="true"></span>
</span>
</a>
<div class="flex justify-center flex-wrap">
@@ -144,4 +144,26 @@
.match {
width: min(100vw, 70em);
}
:global(.sw-nav) {
backdrop-filter: none;
background: transparent;
transition: background 0.3s ease, backdrop-filter 0.3s ease, border-color 0.3s ease;
border-bottom: 1px solid transparent;
}
:global(.sw-nav-scrolled) {
background: rgba(8, 8, 8, 0.85) !important;
backdrop-filter: blur(16px) !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.04) !important;
}
.sw-nav-title {
font-family: "Barlow Condensed", sans-serif;
font-size: 1.3rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: #f5f5f5;
}
</style>

View File

@@ -22,7 +22,7 @@ const {
const postUrl = l(`/announcements/${post.slug.split("/").slice(1).join("/")}`);
---
<Card extraClasses={`w-full items-start mx-0 ${slim ? "m-0 p-1 backdrop-blur-xl bg-transparent" : ""}`} hoverEffect={false}>
<Card extraClasses={`w-full items-start mx-0 ${slim ? "m-0 p-2 backdrop-blur-xl bg-transparent border-0" : "border-t-2 border-t-amber-500/30"}`} hoverEffect={false}>
<div class={`flex flex-row ${slim ? "" : "p-4"}`}>
{
post.data.image != null ? (
@@ -32,7 +32,7 @@ const postUrl = l(`/announcements/${post.slug.split("/").slice(1).join("/")}`);
transition:name={post.data.title + "-image"}
src={post.data.image}
alt="Post Image"
class="rounded-2xl shadow-2xl object-cover h-32 w-32 max-w-none transition-transform hover:scale-105"
class="object-cover h-32 w-32 max-w-none transition-transform hover:scale-105"
/>
</div>
</a>
@@ -40,8 +40,8 @@ const postUrl = l(`/announcements/${post.slug.split("/").slice(1).join("/")}`);
}
<div>
<a href={postUrl} class="flex flex-col items-start">
<h2 class="text-2xl font-bold" transition:name={post.data.title + "-title"}>{post.data.title}</h2>
<P class="text-gray-500"
<h2 class="text-2xl font-bold" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;" transition:name={post.data.title + "-title"}>{post.data.title}</h2>
<P class="text-gray-500 text-sm"
>{
Intl.DateTimeFormat(astroI18n.locale, {
day: "numeric",

View File

@@ -49,14 +49,14 @@
let { open = $bindable(false) }: Props = $props();
</script>
<button transition:fade class="fixed top-0 left-0 w-screen h-screen backdrop-blur z-20 cursor-default" onclick={() => open = false}>
<button transition:fade class="fixed top-0 left-0 w-screen h-screen bg-black/60 backdrop-blur-sm z-20 cursor-default" onclick={() => open = false}>
</button>
<div transition:slide style="width: min(100%, 75em);" class="fixed top-0 left-1/2 -translate-x-1/2 h-2/3 dark:bg-zinc-900 rounded-b-2xl shadow-2xl z-30 p-4 text-white flex flex-col">
<div transition:slide style="width: min(100%, 75em);" class="fixed top-0 left-1/2 -translate-x-1/2 h-2/3 z-30 p-4 text-white flex flex-col sw-search-panel">
<input placeholder="Search..." onkeypress={search}>
<div class="overflow-y-scroll flex-1 w-full mt-2 rounded-2xl">
<div class="overflow-y-scroll flex-1 w-full mt-2">
{#each results as result}
<Card extraClasses="w-full m-0 my-2" hoverEffect={false}>
<Card extraClasses="w-full m-0 my-2 border-t-2 border-t-amber-500/30" hoverEffect={false}>
<a class="grid grid-cols-3" href={l(result.url)}>
<h1>{result.meta.title}</h1>
{#each result.sub_results.slice(0, 2) as sub_result}
@@ -69,13 +69,28 @@
</div>
<style lang="postcss">
.sw-search-panel {
background: rgba(8, 8, 8, 0.95);
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
backdrop-filter: blur(24px);
}
input {
@apply border-2 rounded-md p-2 shadow-2xl w-full
dark:bg-neutral-800
focus:outline-none focus:ring-2 focus:ring-neutral-500 focus:border-transparent;
width: 100%;
padding: 0.7rem 1rem;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.08);
color: #f5f5f5;
font-size: 0.9rem;
outline: none;
transition: border-color 0.2s ease;
}
input:focus {
border-color: rgba(245, 158, 11, 0.5);
}
label {
@apply text-neutral-300;
color: rgba(163, 163, 163, 0.7);
}
</style>

View File

@@ -13,10 +13,10 @@ const {tag, noLink} = Astro.props;
{noLink
? (
<span class="inline-block bg-gray-800 rounded-full px-3 py-1 text-sm font-semibold text-white mr-2 shadow-2xl">{capitalize(tag)}</span>
<span class="inline-block bg-transparent border border-amber-500/30 px-3 py-0.5 text-xs font-semibold text-amber-400 mr-2 uppercase tracking-wider" style="font-family: 'Barlow Condensed', sans-serif;">{capitalize(tag)}</span>
)
: (
<a href={l(`/announcements/tags/${tag}`)}>
<span class="inline-block bg-gray-800 rounded-full px-3 py-1 text-sm font-semibold text-white mr-2 shadow-2xl">{capitalize(tag)}</span>
<span class="inline-block bg-transparent border border-amber-500/30 px-3 py-0.5 text-xs font-semibold text-amber-400 mr-2 uppercase tracking-wider hover:border-amber-400 hover:text-amber-300 transition-colors" style="font-family: 'Barlow Condensed', sans-serif;">{capitalize(tag)}</span>
</a>
)}

View File

@@ -13,7 +13,7 @@
</script>
<div class="flex flex-col gap-1 {unsized ? '' : 'w-72 m-4'}">
<div class="bg-gray-100 text-black font-bold px-2 rounded uppercase">
<div class="bg-amber-500 text-black font-bold px-2 uppercase text-xs tracking-wider" style="font-family: 'Barlow Condensed', sans-serif;">
{title}
</div>
<div class="border border-gray-600 rounded p-2 flex flex-col gap-2 bg-slate-900">

View File

@@ -5,6 +5,7 @@ import { SEO } from "astro-seo";
import { ClientRouter } from "astro:transitions";
const { title, description, clientSideRouter = true, autoDarkMode = true } = Astro.props.frontmatter || Astro.props;
import "../../public/fonts/roboto/roboto.css";
import "../../public/fonts/barlow-condensed/barlow-condensed.css";
---
<html lang={astroI18n.locale} class="dark">
@@ -44,7 +45,7 @@ import "../../public/fonts/roboto/roboto.css";
{clientSideRouter && <ClientRouter />}
</head>
<body class="dark:bg-zinc-800">
<body>
<slot />
</body>
</html>
@@ -54,5 +55,11 @@ import "../../public/fonts/roboto/roboto.css";
font-family: "Roboto", sans-serif;
font-style: normal;
font-weight: 400;
background-color: #080808;
color: #f5f5f5;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Barlow Condensed", sans-serif;
}
</style>

View File

@@ -24,16 +24,14 @@ const { title, description, transparentFooter = true } = Astro.props;
<main class="flex-1" data-pagefind-body>
<slot />
</main>
<footer
class={`min-h-80 mt-4 pb-2 rounded-t-2xl flex flex-col ${transparentFooter ? "backdrop-blur-3xl" : "bg-neutral-900"}`}
style="width: min(100%, 75em); margin-left: auto; margin-right: auto;"
>
<div class="flex-1 flex justify-evenly items-center md:items-start mt-4 md:flex-row flex-col gap-y-4">
<div class="footer-card">
<footer class="sw-footer">
<div class="sw-footer-rule"></div>
<div class="sw-footer-grid">
<div class="sw-footer-col">
<h1>Serverstatus</h1>
<ServerStatus client:only="svelte" />
</div>
<div class="footer-card">
<div class="sw-footer-col">
<h1>Links</h1>
<a href={l("/")}>{t("navbar.links.home.title")}</a>
<a href={l("/join")}>{t("footer.join")}</a>
@@ -44,7 +42,7 @@ const { title, description, transparentFooter = true } = Astro.props;
<a href={l("/privacy-policy")}>{t("footer.privacy")}</a>
<a href={l("/imprint")}>{t("footer.imprint")}</a>
</div>
<div class="footer-card">
<div class="sw-footer-col">
<h1>Social Media</h1>
<a class="flex" href="/youtube">
<YoutubeSolid class="mr-2" />
@@ -60,23 +58,76 @@ const { title, description, transparentFooter = true } = Astro.props;
>
</div>
</div>
<span class="text-sm text-white text-center mt-1">© SteamWar.de - Made with ❤️ by Chaoscaot</span>
<span class="sw-footer-copy">© SteamWar.de</span>
</footer>
</div>
</Fragment>
</Basic>
<style>
.footer-card {
@apply w-40 text-gray-400 flex flex-col;
.sw-footer {
width: min(100%, 75em);
margin: 4rem auto 0;
padding: 0 1rem 1rem;
}
> h1 {
@apply text-xl font-bold text-gray-100;
}
.sw-footer-rule {
height: 1px;
background: linear-gradient(90deg, transparent, rgba(245, 158, 11, 0.3), transparent);
margin-bottom: 2.5rem;
}
> a {
@apply hover:underline;
}
.sw-footer-grid {
display: flex;
justify-content: space-evenly;
align-items: flex-start;
flex-wrap: wrap;
gap: 2rem;
}
.sw-footer-col {
display: flex;
flex-direction: column;
min-width: 10rem;
}
.sw-footer-col > h1 {
font-family: "Barlow Condensed", sans-serif;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.2em;
text-transform: uppercase;
color: #f59e0b;
margin-bottom: 0.75rem;
}
.sw-footer-col > :global(a),
.sw-footer-col > a {
color: rgba(163, 163, 163, 0.85);
font-size: 0.85rem;
line-height: 1.9;
text-decoration: none;
transition: color 0.2s ease;
}
.sw-footer-col > :global(a:hover),
.sw-footer-col > a:hover {
color: #f59e0b;
}
.sw-footer-col > :global(h2) {
font-size: 0.85rem;
color: rgba(163, 163, 163, 0.85);
line-height: 1.9;
}
.sw-footer-copy {
display: block;
text-align: center;
font-size: 0.7rem;
letter-spacing: 0.15em;
color: rgba(163, 163, 163, 0.4);
margin-top: 2.5rem;
}
.match {

View File

@@ -11,10 +11,24 @@ const { title, description, wide = false } = Astro.props;
<BackgroundImage />
</div>
<div
class="mx-auto p-8 rounded-b-md border-x-gray-100 shadow-md pt-14 relative
text-white backdrop-blur-3xl"
class="sw-page-content"
style={wide ? "width: clamp(80%, 75em, 100%);" : "width: min(100%, 75em);"}
>
<slot />
</div>
</NavbarLayout>
<style>
.sw-page-content {
margin: 0 auto;
padding: 3.5rem 2rem 2rem;
position: relative;
color: #f5f5f5;
background: rgba(8, 8, 8, 0.88);
backdrop-filter: blur(24px);
border-left: 1px solid rgba(255, 255, 255, 0.04);
border-right: 1px solid rgba(255, 255, 255, 0.04);
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
min-height: 60vh;
}
</style>

View File

@@ -1,19 +1,17 @@
---
import {type CollectionEntry, getCollection} from "astro:content";
import {astroI18n, createGetStaticPaths} from "astro-i18n";
import { type CollectionEntry, getCollection } from "astro:content";
import { astroI18n, createGetStaticPaths } from "astro-i18n";
import PageLayout from "../layouts/PageLayout.astro";
import LanguageWarning from "../components/LanguageWarning.astro";
import "@styles/table.css";
export const getStaticPaths = createGetStaticPaths(async () => {
let posts = await getCollection("pages", value => value.id.split("/")[0] === astroI18n.locale);
let posts = await getCollection("pages", (value) => value.id.split("/")[0] === astroI18n.locale);
const germanPosts = await getCollection("pages", entry => entry.id.split("/")[0] === astroI18n.fallbackLocale);
const germanPosts = await getCollection("pages", (entry) => entry.id.split("/")[0] === astroI18n.fallbackLocale);
germanPosts.forEach(value => {
if (posts.find(post => post.id.split("/")[1] === value.id.split("/")[1])) {
return;
} else {
germanPosts.forEach((value) => {
if (posts.find((post) => post.id.split("/")[1] !== value.id.split("/")[1])) {
posts.push(value);
}
});
@@ -41,17 +39,15 @@ export const getStaticPaths = createGetStaticPaths(async () => {
}));
});
const {page, german} = Astro.props as { page: CollectionEntry<"pages">, german: boolean };
const {Content} = await page.render();
const { page, german } = Astro.props as { page: CollectionEntry<"pages">; german: boolean };
const { Content } = await page.render();
---
<PageLayout title={page.data.title}>
<article>
{german && (
<LanguageWarning/>
)}
<h1 class="text-left">{page.data.title}</h1>
<Content/>
{german && <LanguageWarning />}
<h1 class="text-left" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;">{page.data.title}</h1>
<Content />
</article>
</PageLayout>
@@ -62,15 +58,28 @@ const {Content} = await page.render();
}
code {
@apply dark:text-neutral-400 text-neutral-800;
color: #fbbf24;
background: rgba(245, 158, 11, 0.08);
padding: 0.15em 0.4em;
}
pre.astro-code {
@apply w-fit p-4 rounded-md border-2 border-gray-600 my-4;
width: fit-content;
padding: 1rem;
margin: 1rem 0;
border: 1px solid rgba(255, 255, 255, 0.06);
background: #080808 !important;
}
a {
@apply text-neutral-800 dark:text-neutral-400 hover:underline;
color: #f59e0b;
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 0.2s ease;
}
a:hover {
border-bottom-color: #f59e0b;
}
}
</style>

View File

@@ -73,13 +73,13 @@ const ogImage = await getImage({
{
post.data.image && (
<div class="absolute top-0 left-0 w-full aspect-video flex justify-center">
<Image src={post.data.image} height="1080" alt="" transition:name={post.data.title + "-image"} class="rounded-2xl linear-fade object-contain h-full" />
<Image src={post.data.image} height="1080" alt="" transition:name={post.data.title + "-image"} class="linear-fade object-contain h-full" />
</div>
)
}
<div class={post.data.image ? "absolute bottom-8 left-2" : "mb-4"}>
<h1 class="text-4xl mb-0" transition:name={post.data.title + "-title"}>{post.data.title}</h1>
<div class="flex items-center mt-2 text-neutral-800 dark:text-neutral-300">
<h1 class="text-4xl mb-0" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;" transition:name={post.data.title + "-title"}>{post.data.title}</h1>
<div class="flex items-center mt-2 text-gray-400">
<TagSolid class="w-4 h-4 mr-2" />
<div transition:name={post.data.title + "-tags"}>
{post.data.tags.map((tag) => <TagComponent tag={tag} />)}
@@ -175,11 +175,17 @@ const ogImage = await getImage({
}
code {
@apply dark:text-neutral-400 text-neutral-800;
color: #fbbf24;
background: rgba(245, 158, 11, 0.08);
padding: 0.15em 0.4em;
}
pre.astro-code {
@apply w-fit p-4 rounded-md border-2 border-gray-600 my-4;
width: fit-content;
padding: 1rem;
margin: 1rem 0;
border: 1px solid rgba(255, 255, 255, 0.06);
background: #080808 !important;
}
}
</style>

View File

@@ -9,21 +9,21 @@ const downloads = await getCollection("downloads");
<PageLayout title="Downloads">
{downloads.map(e => (
<div class="pt-4">
<h1 class="font-bold text-2xl">{e.data.name}</h1>
<div class="py-4">{t(e.data.description)}</div>
<div class="pt-6 pb-4" style="border-bottom: 1px solid rgba(255,255,255,0.04);">
<h1 class="font-bold text-2xl" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.06em;">{e.data.name}</h1>
<div class="py-3 text-gray-400 text-sm">{t(e.data.description)}</div>
<div class="flex flex-col">
<div class="flex flex-col gap-1">
{typeof e.data.url === "object" ?
Object.entries(e.data.url).map(value => (
<a href={value[1].startsWith("/") ? l(value[1]) : value[1]}
class="text-blue-500 hover:underline w-fit">{t(value[0])}</a>
class="text-amber-400 hover:text-amber-300 w-fit text-sm" style="border-bottom: 1px solid transparent; transition: border-color 0.2s;">{t(value[0])}</a>
))
:
<a href={e.data.url} class="text-blue-500 hover:underline w-fit">{t("Download")}</a>
<a href={e.data.url} class="text-amber-400 hover:text-amber-300 w-fit text-sm">{t("Download")}</a>
}
{e.data.sourceUrl ?
<a class="text-blue-500 hover:underline w-fit" href={e.data.sourceUrl}>Quelle</a>
<a class="text-amber-400 hover:text-amber-300 w-fit text-sm" href={e.data.sourceUrl}>Quelle</a>
: null}
</div>
</div>

View File

@@ -9,10 +9,10 @@ let posts = await getCollection("help", entry => entry.id.split("/")[0] === astr
<PageLayout title="Helpcenter">
<div>
<h1>Helpcenter</h1>
<h1 class="text-red-700 text-4xl">WIP!</h1>
<h1 style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.06em;">Helpcenter</h1>
<h1 class="text-amber-500 text-2xl" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.2em; text-transform: uppercase; font-size: 0.8rem;">WIP</h1>
{posts.map(value => (
<a href={l("/help/" + value.slug)}>
<a href={l("/help/" + value.slug)} class="block py-2 text-gray-400 hover:text-amber-400 transition-colors">
<h2>{value.data.title}</h2>
</a>
))}
@@ -21,7 +21,7 @@ let posts = await getCollection("help", entry => entry.id.split("/")[0] === astr
<style>
div {
@apply mx-auto bg-gray-100 px-4 py-8 rounded-b-md shadow-md pt-40 sm:pt-28 md:pt-14
dark:text-white dark:bg-neutral-900;
margin: 0 auto;
padding: 3.5rem 1rem 2rem;
}
</style>

View File

@@ -3,9 +3,7 @@ import dayjs from "dayjs";
import NavbarLayout from "@layouts/NavbarLayout.astro";
import { getCollection } from "astro:content";
import { astroI18n } from "astro-i18n";
import { Image } from "astro:assets";
import Card from "@components/Card.svelte";
import { CaretRight, Pause, Rocket, Crosshair1 } from "@astropub/icons";
import { t } from "astro-i18n";
import { l } from "@utils/util";
@@ -31,194 +29,544 @@ germanPosts.forEach((value) => {
const latestPost = posts.sort((a, b) => dayjs(b.data.created).unix() - dayjs(a.data.created).unix()).at(0);
const prefixColorMap: {
[key: string]: string;
} = {
Admin: "border-red-600 dark:border-red-800 shadow-red-600 dark:shadow-red-800",
Dev: "border-sky-600 dark:border-sky-800 shadow-sky-600 dark:shadow-sky-800",
Mod: "border-amber-600 dark:border-amber-800 shadow-amber-600 dark:shadow-amber-800",
Sup: "border-blue-700 dark:border-blue-900 shadow-blue-700 dark:shadow-blue-900",
Arch: "border-green-500 dark:border-green-700 shadow-green-500 dark:shadow-green-700",
const prefixColors: { [key: string]: string } = {
Admin: "#dc2626",
Dev: "#0284c7",
Mod: "#d97706",
Sup: "#1d4ed8",
Arch: "#22c55e",
};
---
<NavbarLayout title={t("home.page")} description="SteamWar.de Homepage" transparentFooter={false}>
<div class="w-full h-screen relative mb-4 z-10">
<div style="height: calc(100vh + 1rem)">
<!-- ═══════════ HERO ═══════════ -->
<section class="hero">
<div class="hero-bg">
<BackgroundImage />
</div>
<drop-in class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center">
<h1
class="text-4xl sm:text-6xl md:text-8xl font-extrabold text-white -translate-y-16 opacity-0 barlow tracking-wider"
style="transition: transform .7s ease-out, opacity .7s linear; filter: drop-shadow(2px 2px 5px black);"
>
<span class="bg-gradient-to-tr from-yellow-400 to-yellow-300 bg-clip-text text-transparent">{t("home.title.first")}</span><span class="text-neutral-600">{t("home.title.second")}</span>
<div class="hero-gradient"></div>
<div class="hero-scanlines"></div>
<div class="hero-content">
<span class="hero-label">Minecraft PvP Server</span>
<h1 class="hero-title">
<span class="hero-steam">{t("home.title.first")}</span><span class="hero-war">{t("home.title.second")}</span>
</h1>
<text-carousel class="h-20 w-full relative select-none">
<h2 class="-translate-y-16">{t("home.subtitle.1")}</h2>
<div class="hero-rule"></div>
<text-carousel class="hero-carousel">
<h2>{t("home.subtitle.1")}</h2>
<h2>
{t("home.subtitle.2")}
<PlayerCount client:idle />
</h2>
<h2>{t("home.subtitle.3")}</h2>
</text-carousel>
<a href={l("join")} class="btn btn-ghost mt-32 px-8 flex" style="animation: normal flyIn forwards 1.2s ease-out"
>{t("home.join")}
<CaretRight width="24" height="24" />
<a href={l("join")} class="hero-cta">
<span>{t("home.join")}</span>
<CaretRight width="18" height="18" />
</a>
<style>
@keyframes flyIn {
0% {
translate: 0 16px;
opacity: 0;
}
</div>
20% {
translate: 0 16px;
opacity: 0;
}
100% {
translate: 0;
opacity: 1;
}
}
</style>
<script>
class TextCarousel extends HTMLElement {
current = 0;
connectedCallback() {
this._current.classList.add("!opacity-100");
for (let i = 0; i < this.children.length; i++) {
if (i !== this.current) {
this.children[i].classList.add("translate-y-8");
}
}
setInterval(() => {
this.next();
}, 5000);
}
get _current() {
return this.children[this.current];
}
next() {
this._current.classList.remove("!opacity-100");
this._current.classList.add("translate-y-8");
this._current.classList.remove("!delay-500");
this.current = (this.current + 1) % this.children.length;
this._current.classList.add("!opacity-100");
this._current.classList.remove("translate-y-8");
this._current.classList.add("!delay-500");
}
}
class DropIn extends HTMLElement {
connectedCallback() {
for (let child of this.children) {
if (child.classList.contains("opacity-0")) {
child.classList.remove("opacity-0");
child.classList.remove("-translate-y-16");
} else {
child.children[0].classList.remove("opacity-0");
child.children[0].classList.remove("-translate-y-16");
}
}
}
}
customElements.define("text-carousel", TextCarousel);
customElements.define("drop-in", DropIn);
</script>
</drop-in>
<div class="absolute left-1/2 bottom-6 -translate-x-1/2">
<div class="hero-announcement">
<PostComponent post={latestPost} slim={true} />
</div>
</div>
<section class="w-full flex flex-col items-center justify-center shadow-2xl rounded-b-2xl pb-8">
<div class="py-10 flex flex-col lg:flex-row">
<Card client:idle>
<Crosshair1 height="64" width="64" />
<h1>{t("home.benefits.fights.title")}</h1>
<p class="mt-4">{t("home.benefits.fights.description.1")}</p>
<p class="mt-4">{t("home.benefits.fights.description.2")}</p>
</Card>
<Card client:idle>
<Rocket height="64" width="64" />
<h1>{t("home.benefits.bau.title")}</h1>
<p class="mt-4">{t("home.benefits.bau.description")}</p>
</Card>
<Card client:idle>
<Pause height="64" width="64" />
<h1>{t("home.benefits.minigames.title")}</h1>
<p class="mt-4">{t("home.benefits.minigames.description.1")}</p>
<p class="mt-4">{t("home.benefits.minigames.description.2")}</p>
</Card>
</section>
<!-- ═══════════ FEATURES ═══════════ -->
<section class="features">
<div class="features-glow"></div>
<div class="features-inner">
<div class="features-grid">
<article class="feat">
<span class="feat-num">01</span>
<Crosshair1 height="36" width="36" />
<h3>{t("home.benefits.fights.title")}</h3>
<p>{t("home.benefits.fights.description.1")}</p>
<p>{t("home.benefits.fights.description.2")}</p>
</article>
<article class="feat">
<span class="feat-num">02</span>
<Rocket height="36" width="36" />
<h3>{t("home.benefits.bau.title")}</h3>
<p>{t("home.benefits.bau.description")}</p>
</article>
<article class="feat">
<span class="feat-num">03</span>
<Pause height="36" width="36" />
<h3>{t("home.benefits.minigames.title")}</h3>
<p>{t("home.benefits.minigames.description.1")}</p>
<p>{t("home.benefits.minigames.description.2")}</p>
</article>
</div>
</div>
</section>
<section class="w-full py-12 flex flex-wrap justify-center">
{
Object.entries(teamMember).map(([prefix, players]) => (
<Fragment>
{players.map((v, index) => (
<div class="inline-flex flex-col justify-end">
{index == 0 ? <h2 class="dark:text-white text-4xl font-bold text-center md:text-left md:pl-4">{t("home.prefix." + prefix)}</h2> : null}
<Card extraClasses={`pt-8 pb-10 px-8 w-fit shadow-md ${prefixColorMap[prefix]}`} client:idle>
<figure class="flex flex-col items-center" style="width: 150px">
<figcaption class="text-center mb-4 text-2xl">{v.name}</figcaption>
<!-- ═══════════ TEAM ═══════════ -->
<section class="team">
<div class="team-inner">
{
Object.entries(teamMember).map(([prefix, players]) => (
<div class="rank-group">
<h2 class="rank-label" style={`--rc: ${prefixColors[prefix] || "#666"}`}>
{t("home.prefix." + prefix)}
</h2>
<div class="rank-members">
{players.map((v) => (
<div class="member" style={`--rc: ${prefixColors[prefix] || "#666"}`}>
<Image
src={`${import.meta.env.PUBLIC_API_SERVER}/data/skin/${v.uuid}`}
class="transition duration-300 ease-in-out hover:scale-110 hover:backdrop-blur-lg hover:drop-shadow-2xl"
alt={v.name + "s bust"}
width="150"
height="150"
alt={v.name}
width="120"
height="120"
class="w-[100px] h-[100px] transition-transform duration-300"
/>
</figure>
</Card>
<span class="member-name">{v.name}</span>
</div>
))}
</div>
))}
</Fragment>
))
}
</div>
))
}
</div>
</section>
<script>
class TextCarousel extends HTMLElement {
current = 0;
connectedCallback() {
this._current.classList.add("!opacity-100");
for (let i = 0; i < this.children.length; i++) {
if (i !== this.current) {
this.children[i].classList.add("translate-y-4");
}
}
setInterval(() => this.next(), 5000);
}
get _current() {
return this.children[this.current];
}
next() {
this._current.classList.remove("!opacity-100");
this._current.classList.add("translate-y-4");
this._current.classList.remove("!delay-500");
this.current = (this.current + 1) % this.children.length;
this._current.classList.add("!opacity-100");
this._current.classList.remove("translate-y-4");
this._current.classList.add("!delay-500");
}
}
customElements.define("text-carousel", TextCarousel);
</script>
</NavbarLayout>
<style>
text-carousel {
> * {
@apply absolute top-0 left-0 w-full text-xl sm:text-4xl italic text-white text-center opacity-0;
transition:
transform 0.5s ease-out,
opacity 0.5s linear;
text-shadow: 2px 2px 5px black;
/* ── Typography ── */
.hero-label,
.hero-title,
.hero-cta span,
.feat-num,
.feat h3,
.rank-label,
.member-name {
font-family: "Barlow Condensed", sans-serif;
}
/* ══════════════════════════════════════
HERO
══════════════════════════════════════ */
.hero {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
}
.hero-bg {
position: absolute;
inset: 0;
height: calc(100vh + 1rem);
}
.hero-gradient {
position: absolute;
inset: 0;
z-index: 2;
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.6) 0%,
rgba(0, 0, 0, 0.2) 35%,
rgba(0, 0, 0, 0.45) 65%,
#080808 100%
);
}
.hero-scanlines {
position: absolute;
inset: 0;
z-index: 3;
pointer-events: none;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 3px,
rgba(0, 0, 0, 0.06) 3px,
rgba(0, 0, 0, 0.06) 4px
);
}
.hero-content {
position: relative;
z-index: 10;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 1rem;
}
.hero-label {
font-size: 0.65rem;
letter-spacing: 0.5em;
text-transform: uppercase;
color: rgba(245, 158, 11, 0.7);
margin-bottom: 2rem;
animation: fadeUp 0.8s 0.1s ease-out both;
}
@media (min-width: 640px) {
.hero-label { font-size: 0.8rem; }
}
.hero-title {
font-size: clamp(4.5rem, 14vw, 14rem);
font-weight: 900;
line-height: 0.85;
letter-spacing: -0.03em;
user-select: none;
animation: scaleIn 0.9s 0.25s ease-out both;
}
.hero-steam {
background: linear-gradient(160deg, #fcd34d 0%, #f59e0b 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-war {
color: #ffffff;
text-shadow: 0 0 80px rgba(255, 255, 255, 0.06);
}
.hero-rule {
width: 0;
height: 2px;
background: linear-gradient(90deg, transparent, #f59e0b, transparent);
margin: 1.75rem 0;
animation: lineGrow 0.6s 0.7s ease-out both;
}
/* Carousel */
.hero-carousel {
height: 2.5rem;
width: 100%;
max-width: 28rem;
position: relative;
}
@media (min-width: 640px) {
.hero-carousel {
height: 3rem;
max-width: 32rem;
}
}
.barlow {
font-family:
Barlow Condensed,
sans-serif;
text-carousel > * {
position: absolute;
top: 0;
left: 0;
width: 100%;
text-align: center;
opacity: 0;
font-family: "Barlow Condensed", sans-serif;
font-size: 0.95rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.5);
transform: translateY(8px);
transition:
transform 0.5s ease-out,
opacity 0.5s linear;
}
.card {
@apply w-72 border-2 bg-zinc-50 border-gray-100 flex flex-col items-center p-8 m-4 rounded-xl shadow-lg transition-transform duration-300 ease-in-out
dark:bg-zinc-900 dark:border-gray-800 dark:text-gray-100
hover:scale-105;
@media (min-width: 640px) {
text-carousel > * { font-size: 1.15rem; }
}
> h1 {
@apply text-xl font-bold mt-4;
/* CTA */
.hero-cta {
display: inline-flex;
align-items: center;
gap: 0.6rem;
margin-top: 3rem;
padding: 0.8rem 2.8rem;
border: 1px solid rgba(245, 158, 11, 0.5);
color: #fbbf24;
font-size: 0.85rem;
letter-spacing: 0.2em;
text-transform: uppercase;
background: rgba(245, 158, 11, 0.04);
backdrop-filter: blur(12px);
clip-path: polygon(
0 0,
calc(100% - 14px) 0,
100% 14px,
100% 100%,
14px 100%,
0 calc(100% - 14px)
);
transition: all 0.35s ease;
animation: fadeUp 0.6s 1s ease-out both;
}
.hero-cta:hover {
background: rgba(245, 158, 11, 0.12);
border-color: rgba(245, 158, 11, 0.85);
color: #fff;
box-shadow:
0 0 40px rgba(245, 158, 11, 0.1),
inset 0 0 40px rgba(245, 158, 11, 0.03);
transform: scale(1.04);
}
.hero-cta:active {
transform: scale(0.97);
}
/* Announcement */
.hero-announcement {
position: absolute;
bottom: 1.5rem;
left: 50%;
transform: translateX(-50%);
z-index: 20;
width: 100%;
max-width: 40rem;
padding: 0 1rem;
}
/* ══════════════════════════════════════
FEATURES
══════════════════════════════════════ */
.features {
position: relative;
background: #080808;
overflow: hidden;
}
.features-glow {
position: absolute;
top: -100px;
left: 50%;
transform: translateX(-50%);
width: 500px;
height: 250px;
background: radial-gradient(ellipse, rgba(245, 158, 11, 0.06) 0%, transparent 70%);
pointer-events: none;
}
.features-inner {
position: relative;
z-index: 2;
max-width: 64rem;
margin: 0 auto;
padding: 6rem 1rem;
}
.features-grid {
display: grid;
grid-template-columns: 1fr;
gap: 0;
}
@media (min-width: 768px) {
.features-grid {
grid-template-columns: 1fr 1fr 1fr;
}
}
> p {
@apply mt-4;
.feat {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: 2.5rem 2rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
transition: background 0.4s ease;
}
@media (min-width: 768px) {
.feat {
border-bottom: none;
border-right: 1px solid rgba(255, 255, 255, 0.04);
}
.feat:last-child { border-right: none; }
}
> svg {
@apply transition-transform duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl;
.feat:hover {
background: rgba(245, 158, 11, 0.025);
}
.feat-num {
font-size: 3.5rem;
font-weight: 800;
line-height: 1;
color: rgba(245, 158, 11, 0.1);
margin-bottom: 1.25rem;
}
.feat :global(svg) {
color: #f59e0b;
margin-bottom: 1.25rem;
transition: transform 0.3s ease;
}
.feat:hover :global(svg) {
transform: scale(1.15);
}
.feat h3 {
font-size: 1.15rem;
font-weight: 700;
color: #fff;
letter-spacing: 0.08em;
text-transform: uppercase;
margin-bottom: 0.75rem;
}
.feat p {
color: rgba(163, 163, 163, 0.85);
font-size: 0.85rem;
line-height: 1.65;
margin-top: 0.3rem;
}
/* ══════════════════════════════════════
TEAM
══════════════════════════════════════ */
.team {
background: #0c0c0c;
padding: 5rem 0;
}
.team-inner {
max-width: 64rem;
margin: 0 auto;
padding: 0 1rem;
}
.rank-group {
margin-bottom: 3rem;
}
.rank-group:last-child {
margin-bottom: 0;
}
.rank-label {
font-size: 1.35rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--rc);
padding-bottom: 0.6rem;
margin-bottom: 1.25rem;
border-bottom: 2px solid var(--rc);
display: inline-block;
}
.rank-members {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.member {
display: flex;
flex-direction: column;
align-items: center;
padding: 1.25rem 1.5rem;
background: rgba(255, 255, 255, 0.025);
border-top: 2px solid var(--rc);
transition:
transform 0.3s ease,
background 0.3s ease,
box-shadow 0.3s ease;
}
.member:hover {
transform: translateY(-6px);
background: rgba(255, 255, 255, 0.05);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
.member:hover :global(img) {
transform: scale(1.08);
}
.member-name {
margin-top: 0.75rem;
font-size: 0.9rem;
letter-spacing: 0.1em;
color: rgba(212, 212, 212, 0.9);
}
/* ══════════════════════════════════════
ANIMATIONS
══════════════════════════════════════ */
@keyframes fadeUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.92);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes lineGrow {
from {
width: 0;
opacity: 0;
}
to {
width: 6rem;
opacity: 1;
}
}
</style>

View File

@@ -23,8 +23,8 @@ import BackgroundImage from "../components/BackgroundImage.astro";
<div class="h-screen w-screen fixed -z-10">
<BackgroundImage />
</div>
<div class="h-screen mx-auto p-8 rounded-b-md pt-40 sm:pt-28 md:pt-14 flex flex-col justify-center items-center
dark:text-white" style="width: min(100vw, 75em);">
<div class="h-screen mx-auto p-8 pt-40 sm:pt-28 md:pt-14 flex flex-col justify-center items-center"
style="width: min(100vw, 75em);">
<LoginComponent client:load />
</div>
</NavbarLayout>

View File

@@ -4,36 +4,9 @@ import {t} from "astro-i18n";
---
<PageLayout title={t("404.title")}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 400">
<!-- 404 Text - heller für besseren Kontrast -->
<text x="400" y="150" font-family="Arial Black" font-size="120" fill="#ffffff" text-anchor="middle">404</text>
<!-- Trauriger Roboter - hellere Farben für besseren Kontrast -->
<!-- Körper -->
<rect x="350" y="200" width="100" height="120" rx="10" fill="#888888"/>
<!-- Kopf -->
<rect x="365" y="160" width="70" height="60" rx="5" fill="#888888"/>
<!-- Augen -->
<circle cx="385" cy="185" r="8" fill="#ff6b6b"/>
<circle cx="415" cy="185" r="8" fill="#ff6b6b"/>
<!-- Antenne -->
<line x1="400" y1="160" x2="400" y2="140" stroke="#888888" stroke-width="4"/>
<circle cx="400" cy="135" r="5" fill="#888888"/>
<!-- Arme -->
<rect x="320" y="220" width="30" height="10" rx="5" fill="#888888"/>
<rect x="450" y="220" width="30" height="10" rx="5" fill="#888888"/>
<!-- Text unter dem Roboter - heller für besseren Kontrast -->
<text x="400" y="360" font-family="Arial" font-size="24" fill="#ffffff" text-anchor="middle">{t("404.description")}</text>
<!-- Dekorative Elemente - heller für besseren Kontrast -->
<circle cx="250" cy="100" r="5" fill="#bbbbbb"/>
<circle cx="550" cy="150" r="5" fill="#bbbbbb"/>
<circle cx="200" cy="300" r="5" fill="#bbbbbb"/>
<circle cx="600" cy="250" r="5" fill="#bbbbbb"/>
</svg>
<div class="flex flex-col items-center justify-center py-20">
<span style="font-family: 'Barlow Condensed', sans-serif; font-size: clamp(6rem, 15vw, 12rem); font-weight: 900; line-height: 1; color: rgba(245, 158, 11, 0.1);">404</span>
<div style="width: 4rem; height: 2px; background: linear-gradient(90deg, transparent, #f59e0b, transparent); margin: 1.5rem 0;"></div>
<p style="font-family: 'Barlow Condensed', sans-serif; font-size: 1.1rem; letter-spacing: 0.15em; text-transform: uppercase; color: rgba(163, 163, 163, 0.7);">{t("404.description")}</p>
</div>
</PageLayout>

View File

@@ -22,7 +22,7 @@ const { schem }: { schem: CollectionEntry<"publics">} = Astro.props;
---
<PageLayout title={schem.data.name}>
<h1 class="text-5xl font-bold w-fit" transition:name={schem.data.id + "-title"}>{schem.data.name}</h1>
<h1 class="text-5xl font-bold w-fit" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;" transition:name={schem.data.id + "-title"}>{schem.data.name}</h1>
<PublicPreview client:idle pub={schem} imageHeight={schem.data.image.height}>
<Image class="object-contain" transition:name={schem.data.id + "-img"} src={schem.data.alt || schem.data.image} alt={schem.data.name}></Image>
</PublicPreview>

View File

@@ -27,18 +27,18 @@ const publics = await getCollection("publics", entry => entry.data.gamemode.id =
---
<PageLayout title="Publics">
<h1 class="text-4xl font-bold">{t(`${mode.data.translationKey}.title`)}</h1>
<div class="grid grid-cols-2 gap-2">
<h1 class="text-4xl font-bold" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;">{t(`${mode.data.translationKey}.title`)}</h1>
<div class="grid grid-cols-2 gap-2 mt-4">
{publics.map((pub) => (
<a href={l("/publics/" + pub.id)}>
<Card extraClasses="w-full m-0" hoverEffect={false}>
<Card extraClasses="w-full m-0 border-t-2 border-t-amber-500/30" hoverEffect={false}>
<div class="flex justify-center">
<XRayPreview client:load>
<Image style="width: 500px" slot="normal" src={pub.data.image} alt={pub.data.name} transition:name={pub.data.id + "-img"} />
{pub.data.xray && <Image slot="xray" class="bg-zinc-50 dark:bg-zinc-900" src={pub.data.xray} alt={pub.data.name} />}
{pub.data.xray && <Image slot="xray" src={pub.data.xray} alt={pub.data.name} />}
</XRayPreview>
</div>
<h2 class="font-bold text-3xl" transition:name={pub.data.id + "-title"}>{pub.data.name}</h2>
<h2 class="font-bold text-3xl" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;" transition:name={pub.data.id + "-title"}>{pub.data.name}</h2>
</Card>
</a>
))}

View File

@@ -25,6 +25,6 @@ const {mode} = Astro.props;
---
<PageLayout title={t("ranking.heading", {mode: t(`${mode.data.translationKey}.title`)})}>
<h1 class="text-2xl mb-2">{t("ranking.heading", {mode: t(`${mode.data.translationKey}.title`)})}</h1>
<h1 class="text-2xl mb-2" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.06em;">{t("ranking.heading", {mode: t(`${mode.data.translationKey}.title`)})}</h1>
<EloTable gamemode={mode.id} client:load/>
</PageLayout>

View File

@@ -50,23 +50,23 @@ const {Content} = await page.render();
---
<PageLayout title={t("rules.title", {mode: t(`${page.data.translationKey}.title`)})}>
<h1 class="text-3xl font-bold">{t(`${page.data.translationKey}.title`)}</h1>
<h1 class="text-3xl font-bold" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;">{t(`${page.data.translationKey}.title`)}</h1>
{mode && mode.data.ranked && (
<Fragment>
<EloTable gamemode={page.id.split("/")[1].split(".")[0]} client:load topFive={true}/>
<a class="text-neutral-800 dark:text-neutral-400 hover:underline" href={l(`/rangliste/${page.id.split("/")[1].split(".")[0]}`)}>{t("rules.ranking")}</a>
<a class="text-amber-400 hover:text-amber-300 transition-colors text-sm" href={l(`/rangliste/${page.id.split("/")[1].split(".")[0]}`)}>{t("rules.ranking")}</a>
</Fragment>
)}
{publics && publics.length != 0 && (
<Fragment>
<div class="flex overflow-x-scroll">
<div class="flex overflow-x-scroll gap-2 py-4">
{publics.map(value => (
<a href={l(`/publics/${value.id}`)} style="display: contents">
<Image src={value.data.image} alt={value.data.name} height={300} width={300} class="drop-shadow"></Image>
<Image src={value.data.image} alt={value.data.name} height={300} width={300}></Image>
</a>
))}
</div>
<a class="text-neutral-800 dark:text-neutral-400 hover:underline" href={l(`/publics/${page.id.split("/")[1].split(".")[0]}`)}>{t("rules.publics")}</a>
<a class="text-amber-400 hover:text-amber-300 transition-colors text-sm" href={l(`/publics/${page.id.split("/")[1].split(".")[0]}`)}>{t("rules.publics")}</a>
</Fragment>
)}
<article>
@@ -84,15 +84,28 @@ const {Content} = await page.render();
}
code {
@apply dark:text-neutral-400 text-neutral-800;
color: #fbbf24;
background: rgba(245, 158, 11, 0.08);
padding: 0.15em 0.4em;
}
pre.astro-code {
@apply w-fit p-4 rounded-md border-2 border-gray-600 my-4;
width: fit-content;
padding: 1rem;
margin: 1rem 0;
border: 1px solid rgba(255, 255, 255, 0.06);
background: #080808 !important;
}
a {
@apply text-neutral-800 dark:text-neutral-400 hover:underline;
color: #f59e0b;
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 0.2s ease;
}
a:hover {
border-bottom-color: #f59e0b;
}
}

View File

@@ -24,25 +24,47 @@ const modes = await getCollection("modes", entry => entry.data.main);
<PageLayout title={t("rules.page")}>
{modes.map(value => (
<div class="dark:bg-neutral-800 rounded-md p-4 border border-neutral-400 shadow-md my-4 flex flex-col
md:flex-row">
<div class="sw-mode-card">
<a href={l(`/publics/${imageMap[value.data.translationKey].id}`)}>
<Image height="200" width="200" src={imageMap[value.data.translationKey].data.image}
alt={t("rules." + value.data.translationKey + ".title")} class="h-full aspect-square max-w-fit"></Image>
</a>
<div class="ml-4">
<a href={l(`/rules/${value.id}`)}>
<h1 class="text-2xl font-bold">{t(value.data.translationKey + ".title")}</h1>
<div>{t("rules." + value.data.translationKey + ".description")}</div>
<h1 class="text-2xl font-bold" style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.04em;">{t(value.data.translationKey + ".title")}</h1>
<div class="text-gray-400 text-sm mt-1">{t("rules." + value.data.translationKey + ".description")}</div>
</a>
<div class="mt-2 flex flex-col">
<a href={l(`/publics/${value.id}`)} class="text-yellow-300 hover:underline w-fit">{t("rules.publics")}</a>
<div class="mt-2 flex flex-col gap-0.5">
<a href={l(`/publics/${value.id}`)} class="text-amber-400 hover:text-amber-300 w-fit text-sm transition-colors">{t("rules.publics")}</a>
{value.data.ranked
? <a href={l(`/ranked/${value.id}`)}
class="text-yellow-300 hover:underline w-fit">{t("rules.ranking")}</a>
class="text-amber-400 hover:text-amber-300 w-fit text-sm transition-colors">{t("rules.ranking")}</a>
: null}
</div>
</div>
</div>))}
<a href={l("/rangliste/MissileWars")}>MissileWars Rangliste</a>
</PageLayout>
<a href={l("/rangliste/MissileWars")} class="text-amber-400 hover:text-amber-300 transition-colors">MissileWars Rangliste</a>
</PageLayout>
<style>
.sw-mode-card {
display: flex;
flex-direction: column;
padding: 1.25rem;
margin: 1rem 0;
border: 1px solid rgba(255, 255, 255, 0.06);
border-top: 2px solid rgba(245, 158, 11, 0.3);
background: rgba(255, 255, 255, 0.02);
transition: background 0.3s ease;
}
.sw-mode-card:hover {
background: rgba(245, 158, 11, 0.03);
}
@media (min-width: 768px) {
.sw-mode-card {
flex-direction: row;
}
}
</style>

View File

@@ -5,6 +5,6 @@ import {t} from "astro-i18n";
---
<PageLayout title={t("stats.title")}>
<h1>{t("stats.title")}</h1>
<h1 style="font-family: 'Barlow Condensed', sans-serif; letter-spacing: 0.06em;">{t("stats.title")}</h1>
<FightStatistics client:only="svelte"/>
</PageLayout>

View File

@@ -23,67 +23,77 @@
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--background: 0 0% 3.1%;
--foreground: 0 0% 96%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--muted: 0 0% 10%;
--muted-foreground: 0 0% 55%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--popover: 0 0% 5%;
--popover-foreground: 0 0% 96%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--card: 0 0% 5%;
--card-foreground: 0 0% 96%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--border: 0 0% 12%;
--input: 0 0% 12%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--primary: 38 92% 50%;
--primary-foreground: 0 0% 4%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--secondary: 0 0% 10%;
--secondary-foreground: 0 0% 96%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--accent: 38 92% 50%;
--accent-foreground: 0 0% 4%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--ring: 240 5% 64.9%;
--ring: 38 92% 50%;
--radius: 0.5rem;
--radius: 0;
--sw-bg: #080808;
--sw-bg-raised: #0c0c0c;
--sw-bg-surface: #111111;
--sw-amber: #f59e0b;
--sw-amber-light: #fbbf24;
--sw-amber-dim: rgba(245, 158, 11, 0.15);
--sw-text: #f5f5f5;
--sw-text-muted: #a3a3a3;
--sw-border: rgba(255, 255, 255, 0.06);
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--background: 0 0% 3.1%;
--foreground: 0 0% 96%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--muted: 0 0% 10%;
--muted-foreground: 0 0% 55%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--popover: 0 0% 5%;
--popover-foreground: 0 0% 96%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--card: 0 0% 5%;
--card-foreground: 0 0% 96%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--border: 0 0% 12%;
--input: 0 0% 12%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--primary: 38 92% 50%;
--primary-foreground: 0 0% 4%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--secondary: 0 0% 10%;
--secondary-foreground: 0 0% 96%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--accent: 38 92% 50%;
--accent-foreground: 0 0% 4%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 85.7% 97.3%;
--ring: 240 3.7% 15.9%;
--ring: 38 92% 50%;
}
}
@@ -93,6 +103,13 @@
}
body {
@apply bg-background text-foreground;
background-color: var(--sw-bg);
color: var(--sw-text);
}
::selection {
background: rgba(245, 158, 11, 0.3);
color: #fff;
}
article {
@@ -101,15 +118,26 @@
}
code {
@apply dark:text-neutral-400 text-neutral-800;
color: var(--sw-amber-light);
background: rgba(245, 158, 11, 0.08);
padding: 0.15em 0.4em;
}
pre.astro-code {
@apply w-fit p-4 rounded-md border-2 border-gray-600 my-4;
@apply w-fit p-4 my-4;
border: 1px solid var(--sw-border);
background: var(--sw-bg) !important;
}
a {
@apply text-neutral-800 dark:text-neutral-400 hover:underline;
color: var(--sw-amber);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 0.2s ease;
}
a:hover {
border-bottom-color: var(--sw-amber);
}
}
}

View File

@@ -18,56 +18,137 @@
*/
.btn {
@apply bg-yellow-400 font-bold py-2 px-4 rounded cursor-pointer select-none mx-0.5 md:mx-2 text-black flex flex-row;
@apply hover:bg-yellow-300 hover:text-black hover:shadow-2xl hover:scale-105;
transition: all 0.5s cubic-bezier(.2, 3, .67, .6),
background-color .1s ease-in-out,
outline-width .1s ease-in-out,
outline-color .1s ease-in-out;
@apply active:scale-90;
display: inline-flex;
align-items: center;
gap: 0.4rem;
font-family: "Barlow Condensed", sans-serif;
font-weight: 700;
font-size: 0.8rem;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 0.5rem 1.2rem;
color: #f5f5f5;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
cursor: pointer;
user-select: none;
transition: all 0.25s ease;
clip-path: polygon(
0 0,
calc(100% - 8px) 0,
100% 8px,
100% 100%,
8px 100%,
0 calc(100% - 8px)
);
.btn__text {
@apply inline-block;
display: inline-block;
}
}
.btn:hover {
background: rgba(245, 158, 11, 0.08);
border-color: rgba(245, 158, 11, 0.4);
color: #fbbf24;
}
.btn:active {
transform: scale(0.96);
}
.btn-dropdown {
@apply relative mx-0.5 md:mx-2;
position: relative;
> :nth-child(1) {
@apply !mx-0;
}
> :nth-child(2) {
@apply hidden absolute top-full left-1/2 -translate-x-1/2 bg-gray-800 list-none text-white rounded py-2 flex-col text-sm z-20;
display: none;
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
background: #111111;
border: 1px solid rgba(255, 255, 255, 0.06);
list-style: none;
padding: 0.5rem 0;
flex-direction: column;
font-size: 0.8rem;
z-index: 20;
min-width: 10rem;
}
> :nth-child(2) .btn {
clip-path: none;
width: 100%;
justify-content: flex-start;
border: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
}
&:hover, &:focus-within {
> :nth-child(2) {
@apply flex;
display: flex;
}
}
}
.btn-ghost {
@apply px-6 text-xl;
@apply bg-transparent border-2 border-yellow-400 shadow-2xl shadow-yellow-400 backdrop-blur text-neutral-800 font-bold bg-gradient-to-br from-yellow-400 to-yellow-200 rounded-xl;
@apply hover:border-yellow-300 hover:shadow-yellow-800 hover:scale-110;
padding: 0.8rem 2.8rem;
font-size: 0.85rem;
letter-spacing: 0.2em;
color: #fbbf24;
background: rgba(245, 158, 11, 0.04);
border: 1px solid rgba(245, 158, 11, 0.5);
backdrop-filter: blur(12px);
clip-path: polygon(
0 0,
calc(100% - 14px) 0,
100% 14px,
100% 100%,
14px 100%,
0 calc(100% - 14px)
);
}
.btn-ghost:hover {
background: rgba(245, 158, 11, 0.12);
border-color: rgba(245, 158, 11, 0.85);
color: #fff;
box-shadow: 0 0 40px rgba(245, 158, 11, 0.1);
transform: scale(1.04);
}
.btn-gray {
@apply bg-gray-800 text-white;
background: transparent;
border-color: rgba(255, 255, 255, 0.06);
color: rgba(212, 212, 212, 0.9);
}
.btn-gray:hover {
background: rgba(245, 158, 11, 0.06);
border-color: rgba(245, 158, 11, 0.3);
color: #fbbf24;
}
.btn-neutral {
@apply bg-neutral-800 text-white;
background: rgba(255, 255, 255, 0.04);
border-color: rgba(255, 255, 255, 0.08);
color: #f5f5f5;
}
.btn-text {
@apply bg-transparent underline text-white;
@apply hover:bg-transparent hover:outline hover:outline-1;
.btn__text {
@apply underline;
}
background: transparent;
border: none;
clip-path: none;
color: #f59e0b;
text-decoration: none;
border-bottom: 1px solid transparent;
}
.btn-text:hover {
background: transparent;
border-bottom-color: #f59e0b;
color: #fbbf24;
}

View File

@@ -18,20 +18,42 @@
*/
table {
@apply w-full overflow-clip;
:not(:has([data-no-head])) {
}
width: 100%;
overflow: clip;
border-collapse: collapse;
thead {
border-bottom: 1px solid white;
border-bottom: 2px solid rgba(245, 158, 11, 0.3);
font-family: "Barlow Condensed", sans-serif;
font-size: 0.7rem;
letter-spacing: 0.15em;
text-transform: uppercase;
color: #f59e0b;
}
thead th {
padding: 0.6rem 0.8rem;
text-align: left;
}
tbody {
text-align: center;
}
tr:nth-child(odd) {
@apply backdrop-brightness-125;
}
tbody td {
padding: 0.5rem 0.8rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
}
tbody tr {
transition: background 0.2s ease;
}
tbody tr:nth-child(odd) {
background: rgba(255, 255, 255, 0.02);
}
tbody tr:hover {
background: rgba(245, 158, 11, 0.04);
}
}

View File

@@ -74,7 +74,8 @@ const config = {
sm: "calc(var(--radius) - 4px)",
},
fontFamily: {
sans: [...fontFamily.sans],
sans: ["Roboto", ...fontFamily.sans],
display: ["Barlow Condensed", ...fontFamily.sans],
},
},
},