Compare commits
11 Commits
develop/da
...
fd3d621fd5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd3d621fd5 | ||
| 6377799e1b | |||
| b3598e1ee1 | |||
| b9db5be858 | |||
| 3e54934806 | |||
| 98638f94fc | |||
| 4da8fe50c0 | |||
| 7757978668 | |||
| 9eea0b2b3f | |||
| 063638d016 | |||
| f5a778d9b4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,3 +26,4 @@ pnpm-debug.log*
|
|||||||
/src/env.d.ts
|
/src/env.d.ts
|
||||||
/src/pages/en/
|
/src/pages/en/
|
||||||
/.idea
|
/.idea
|
||||||
|
pnpm-lock.yaml
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"@astrojs/tailwind": "^5.1.5",
|
"@astrojs/tailwind": "^5.1.5",
|
||||||
"@astropub/icons": "^0.2.0",
|
"@astropub/icons": "^0.2.0",
|
||||||
"@internationalized/date": "^3.7.0",
|
"@internationalized/date": "^3.7.0",
|
||||||
|
"@lucide/svelte": "^0.488.0",
|
||||||
"@types/color": "^4.2.0",
|
"@types/color": "^4.2.0",
|
||||||
"@types/node": "^22.9.3",
|
"@types/node": "^22.9.3",
|
||||||
"@types/three": "^0.170.0",
|
"@types/three": "^0.170.0",
|
||||||
|
|||||||
9276
pnpm-lock.yaml
generated
9276
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -18,13 +18,13 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {twMerge} from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
import {onMount} from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
let cardElement: HTMLDivElement = $state();
|
let cardElement: HTMLDivElement = $state();
|
||||||
|
|
||||||
function rotateElement(event: MouseEvent) {
|
function rotateElement(event: MouseEvent) {
|
||||||
if(!hoverEffect) return;
|
if (!hoverEffect) return;
|
||||||
|
|
||||||
const x = event.clientX;
|
const x = event.clientX;
|
||||||
const y = event.clientY;
|
const y = event.clientY;
|
||||||
@@ -36,23 +36,23 @@
|
|||||||
const rotateX = (centerY - y) / 20;
|
const rotateX = (centerY - y) / 20;
|
||||||
const rotateY = -(centerX - x) / 20;
|
const rotateY = -(centerX - x) / 20;
|
||||||
|
|
||||||
cardElement.style.setProperty('--rotate-x', `${rotateX}deg`);
|
cardElement.style.setProperty("--rotate-x", `${rotateX}deg`);
|
||||||
cardElement.style.setProperty('--rotate-y', `${rotateY}deg`);
|
cardElement.style.setProperty("--rotate-y", `${rotateY}deg`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetElement() {
|
function resetElement() {
|
||||||
cardElement.style.setProperty('--rotate-x', "0");
|
cardElement.style.setProperty("--rotate-x", "0");
|
||||||
cardElement.style.setProperty('--rotate-y', "0");
|
cardElement.style.setProperty("--rotate-y", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
hoverEffect?: boolean;
|
hoverEffect?: boolean;
|
||||||
extraClasses?: string;
|
extraClasses?: string;
|
||||||
children?: import('svelte').Snippet;
|
children?: import("svelte").Snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { hoverEffect = true, extraClasses = '', children }: Props = $props();
|
let { hoverEffect = true, extraClasses = "", children }: Props = $props();
|
||||||
let classes = $derived(twMerge("w-72 border-2 bg-zinc-50 border-gray-100 flex flex-col items-center p-8 m-4 rounded-xl shadow-lg dark:bg-zinc-900 dark:border-gray-800 dark:text-gray-100", extraClasses))
|
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));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={classes} bind:this={cardElement} onmousemove={rotateElement} onmouseleave={resetElement} class:hoverEffect>
|
<div class={classes} bind:this={cardElement} onmousemove={rotateElement} onmouseleave={resetElement} class:hoverEffect>
|
||||||
@@ -61,20 +61,20 @@
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
div {
|
div {
|
||||||
transform: perspective(1000px) rotateX(var(--rotate-x, 0)) rotateY(var(--rotate-y, 0)) !important;
|
transform: perspective(1000px) rotateX(var(--rotate-x, 0)) rotateY(var(--rotate-y, 0)) !important;
|
||||||
|
|
||||||
transition: scale 300ms cubic-bezier(.2, 3, .67, .6);
|
transition: scale 300ms cubic-bezier(0.2, 3, 0.67, 0.6);
|
||||||
|
|
||||||
:global(h1) {
|
:global(h1) {
|
||||||
@apply text-xl font-bold mt-4;
|
@apply text-xl font-bold mt-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(svg) {
|
:global(svg) {
|
||||||
@apply transition-transform duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl
|
@apply transition-transform duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.hoverEffect:hover {
|
.hoverEffect:hover {
|
||||||
scale: 105%;
|
scale: 105%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import FightStatsChart from "./FightStatsChart.svelte";
|
import FightStatsChart from "./FightStatsChart.svelte";
|
||||||
import {t} from "astro-i18n";
|
import { t } from "astro-i18n";
|
||||||
import {statsRepo} from "@repo/stats.ts";
|
import { statsRepo } from "@repo/stats.ts";
|
||||||
|
|
||||||
let request = getStats();
|
let request = getStats();
|
||||||
|
|
||||||
@@ -35,4 +35,4 @@
|
|||||||
<FightStatsChart data={stats} />
|
<FightStatsChart data={stats} />
|
||||||
{:catch error}
|
{:catch error}
|
||||||
<p>error: {error}</p>
|
<p>error: {error}</p>
|
||||||
{/await}
|
{/await}
|
||||||
|
|||||||
@@ -19,18 +19,18 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "../styles/button.css";
|
import "../styles/button.css";
|
||||||
import {CaretDownOutline, SearchOutline} from "flowbite-svelte-icons";
|
import { CaretDownOutline, SearchOutline } from "flowbite-svelte-icons";
|
||||||
import {t} from "astro-i18n";
|
import { t } from "astro-i18n";
|
||||||
import {l} from "../util/util";
|
import { l } from "../util/util";
|
||||||
import {onMount} from "svelte";
|
import { onMount } from "svelte";
|
||||||
import {loggedIn} from "@repo/authv2.ts";
|
import { loggedIn } from "@repo/authv2.ts";
|
||||||
interface Props {
|
interface Props {
|
||||||
logo?: import('svelte').Snippet;
|
logo?: import("svelte").Snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { logo }: Props = $props();
|
let { logo }: Props = $props();
|
||||||
|
|
||||||
let navbar = $state<HTMLDivElement>();
|
let navbar = $state<HTMLElement>();
|
||||||
let searchOpen = $state(false);
|
let searchOpen = $state(false);
|
||||||
|
|
||||||
let accountBtn = $state<HTMLAnchorElement>();
|
let accountBtn = $state<HTMLAnchorElement>();
|
||||||
@@ -41,11 +41,11 @@
|
|||||||
} else {
|
} else {
|
||||||
accountBtn!.href = l("/login");
|
accountBtn!.href = l("/login");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
handleScroll();
|
handleScroll();
|
||||||
})
|
});
|
||||||
|
|
||||||
function handleScroll() {
|
function handleScroll() {
|
||||||
if (window.scrollY > 0) {
|
if (window.scrollY > 0) {
|
||||||
@@ -56,13 +56,17 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window onscroll={handleScroll}/>
|
<svelte:window onscroll={handleScroll} />
|
||||||
|
|
||||||
<nav data-pagefind-ignore class="fixed top-0 left-0 right-0 sm:px-4 py-1 transition-colors z-10 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" bind:this={navbar}>
|
<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"
|
||||||
|
bind:this={navbar}
|
||||||
|
>
|
||||||
<div class="flex flex-row items-center justify-evenly md:justify-between match">
|
<div class="flex flex-row items-center justify-evenly md:justify-between match">
|
||||||
<a class="flex items-center" href={l("/")}>
|
<a class="flex items-center" href={l("/")}>
|
||||||
{@render logo?.()}
|
{@render logo?.()}
|
||||||
<span class="text-2xl uppercase font-bold dark:text-white hidden md:inline-block">
|
<span class="text-2xl uppercase font-bold text-white hidden md:inline-block">
|
||||||
{t("navbar.title")}
|
{t("navbar.title")}
|
||||||
<span class="before:scale-y-100" style="display: none" aria-hidden="true"></span>
|
<span class="before:scale-y-100" style="display: none" aria-hidden="true"></span>
|
||||||
</span>
|
</span>
|
||||||
@@ -73,7 +77,7 @@
|
|||||||
<a href={l("/")}>
|
<a href={l("/")}>
|
||||||
<span class="btn__text">{t("navbar.links.home.title")}</span>
|
<span class="btn__text">{t("navbar.links.home.title")}</span>
|
||||||
</a>
|
</a>
|
||||||
<CaretDownOutline class="ml-2 mt-auto"/>
|
<CaretDownOutline class="ml-2 mt-auto" />
|
||||||
</button>
|
</button>
|
||||||
<div>
|
<div>
|
||||||
<a class="btn btn-gray" href={l("/announcements")}>{t("navbar.links.home.announcements")}</a>
|
<a class="btn btn-gray" href={l("/announcements")}>{t("navbar.links.home.announcements")}</a>
|
||||||
@@ -87,7 +91,7 @@
|
|||||||
<a rel="prefetch" href={l("/rules")}>
|
<a rel="prefetch" href={l("/rules")}>
|
||||||
<span class="btn__text">{t("navbar.links.rules.title")}</span>
|
<span class="btn__text">{t("navbar.links.rules.title")}</span>
|
||||||
</a>
|
</a>
|
||||||
<CaretDownOutline class="ml-2 mt-auto"/>
|
<CaretDownOutline class="ml-2 mt-auto" />
|
||||||
</button>
|
</button>
|
||||||
<div>
|
<div>
|
||||||
<a href={l("/rules/wargear")} class="btn btn-gray">{t("navbar.links.rules.wg")}</a>
|
<a href={l("/rules/wargear")} class="btn btn-gray">{t("navbar.links.rules.wg")}</a>
|
||||||
@@ -96,10 +100,8 @@
|
|||||||
<a href={l("/rules/airship")} class="btn btn-gray">{t("navbar.links.rules.as")}</a>
|
<a href={l("/rules/airship")} class="btn btn-gray">{t("navbar.links.rules.as")}</a>
|
||||||
<a href={l("/rules/quickgear")} class="btn btn-gray">{t("navbar.links.rules.qg")}</a>
|
<a href={l("/rules/quickgear")} class="btn btn-gray">{t("navbar.links.rules.qg")}</a>
|
||||||
<h2 class="px-2 text-gray-300">{t("navbar.links.rules.rotating")}</h2>
|
<h2 class="px-2 text-gray-300">{t("navbar.links.rules.rotating")}</h2>
|
||||||
<a href={l("/rules/megawargear")}
|
<a href={l("/rules/megawargear")} class="btn btn-gray">{t("navbar.links.rules.megawg")}</a>
|
||||||
class="btn btn-gray">{t("navbar.links.rules.megawg")}</a>
|
<a href={l("/rules/microwargear")} class="btn btn-gray">{t("navbar.links.rules.micro")}</a>
|
||||||
<a href={l("/rules/microwargear")}
|
|
||||||
class="btn btn-gray">{t("navbar.links.rules.micro")}</a>
|
|
||||||
<a href={l("/rules/streetfight")} class="btn btn-gray">{t("navbar.links.rules.sf")}</a>
|
<a href={l("/rules/streetfight")} class="btn btn-gray">{t("navbar.links.rules.sf")}</a>
|
||||||
<h2 class="px-2 text-gray-300">{t("navbar.links.rules.ranked")}</h2>
|
<h2 class="px-2 text-gray-300">{t("navbar.links.rules.ranked")}</h2>
|
||||||
<a href={l("/rangliste/missilewars")} class="btn btn-gray">{t("navbar.links.ranked.mw")}</a>
|
<a href={l("/rangliste/missilewars")} class="btn btn-gray">{t("navbar.links.ranked.mw")}</a>
|
||||||
@@ -141,4 +143,4 @@
|
|||||||
.match {
|
.match {
|
||||||
width: min(100vw, 70em);
|
width: min(100vw, 70em);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,50 +1,60 @@
|
|||||||
---
|
---
|
||||||
import type {CollectionEntry} from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import {l} from "../util/util";
|
import { l } from "../util/util";
|
||||||
import {astroI18n} from "astro-i18n";
|
import { astroI18n } from "astro-i18n";
|
||||||
import {Image} from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import TagComponent from "./TagComponent.astro";
|
import TagComponent from "./TagComponent.astro";
|
||||||
import P from "./P.astro";
|
import P from "./P.astro";
|
||||||
import Card from "@components/Card.svelte";
|
import Card from "@components/Card.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
post: CollectionEntry<"announcements">
|
post: CollectionEntry<"announcements">;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { post, slim }: {
|
const {
|
||||||
post: CollectionEntry<"announcements">,
|
post,
|
||||||
slim: boolean,
|
slim,
|
||||||
|
}: {
|
||||||
|
post: CollectionEntry<"announcements">;
|
||||||
|
slim: boolean;
|
||||||
} = Astro.props as Props;
|
} = Astro.props as Props;
|
||||||
|
|
||||||
const postUrl = l(`/announcements/${post.slug.split("/").slice(1).join("/")}`);
|
const postUrl = l(`/announcements/${post.slug.split("/").slice(1).join("/")}`);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Card extraClasses={`w-full items-start mx-0 ${slim ? "m-0 p-1" : ""}`} hoverEffect={false}>
|
<Card extraClasses={`w-full items-start mx-0 ${slim ? "m-0 p-1 backdrop-blur-xl bg-transparent" : ""}`} hoverEffect={false}>
|
||||||
<div class={`flex flex-row ${slim ? "":"p-4"}`}>
|
<div class={`flex flex-row ${slim ? "" : "p-4"}`}>
|
||||||
{post.data.image != null
|
{
|
||||||
? (
|
post.data.image != null ? (
|
||||||
<a href={postUrl}>
|
<a href={postUrl}>
|
||||||
<div class="flex-shrink-0 pr-2">
|
<div class="flex-shrink-0 pr-2">
|
||||||
<Image 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" />
|
<Image
|
||||||
|
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"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
)
|
) : null
|
||||||
: null}
|
}
|
||||||
<div>
|
<div>
|
||||||
<a href={postUrl} class="flex flex-col items-start">
|
<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>
|
<h2 class="text-2xl font-bold" transition:name={post.data.title + "-title"}>{post.data.title}</h2>
|
||||||
<P class="text-gray-500">{Intl.DateTimeFormat(astroI18n.locale, {
|
<P class="text-gray-500"
|
||||||
day: "numeric",
|
>{
|
||||||
month: "long",
|
Intl.DateTimeFormat(astroI18n.locale, {
|
||||||
year: "numeric",
|
day: "numeric",
|
||||||
}).format(post.data.created)}</P>
|
month: "long",
|
||||||
|
year: "numeric",
|
||||||
|
}).format(post.data.created)
|
||||||
|
}</P
|
||||||
|
>
|
||||||
<P>{post.data.description}</P>
|
<P>{post.data.description}</P>
|
||||||
</a>
|
</a>
|
||||||
<div class="mt-1" transition:name={post.data.title + "-tags"}>
|
<div class="mt-1" transition:name={post.data.title + "-tags"}>
|
||||||
{post.data.tags.map((tag) => (
|
{post.data.tags.map((tag) => <TagComponent tag={tag} />)}
|
||||||
<TagComponent tag={tag} />
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -18,24 +18,35 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {Input} from "@components/ui/input";
|
import { Input } from "@components/ui/input";
|
||||||
import {Label} from "@components/ui/label";
|
import { Label } from "@components/ui/label";
|
||||||
import {Popover, PopoverContent, PopoverTrigger} from "@components/ui/popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover";
|
||||||
import type {SWEvent} from "@type/event.ts"
|
import type { SWEvent } from "@type/event.ts";
|
||||||
import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte";
|
import DateTimePicker from "@components/ui/datetime-picker/DateTimePicker.svelte";
|
||||||
import {fromAbsolute} from "@internationalized/date";
|
import { fromAbsolute } from "@internationalized/date";
|
||||||
import {Button} from "@components/ui/button";
|
import { Button, buttonVariants } from "@components/ui/button";
|
||||||
import {ChevronsUpDown} from "lucide-svelte";
|
import { ChevronsUpDown } from "lucide-svelte";
|
||||||
import {Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList} from "@components/ui/command";
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@components/ui/command";
|
||||||
import {schemTypes} from "@stores/stores.ts";
|
import { schemTypes } from "@stores/stores.ts";
|
||||||
import Check from "lucide-svelte/icons/check";
|
import Check from "lucide-svelte/icons/check";
|
||||||
import {cn} from "@components/utils.ts";
|
import { cn } from "@components/utils.ts";
|
||||||
import {Switch} from "@components/ui/switch";
|
import { Switch } from "@components/ui/switch";
|
||||||
import {eventRepo} from "@repo/event.ts";
|
import { eventRepo } from "@repo/event.ts";
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
AlertDialogTrigger,
|
||||||
|
} from "@components/ui/alert-dialog";
|
||||||
|
|
||||||
const { event }: { event: SWEvent } = $props();
|
const { event }: { event: SWEvent } = $props();
|
||||||
|
|
||||||
let rootEvent: SWEvent = $state(event)
|
let rootEvent: SWEvent = $state(event);
|
||||||
|
|
||||||
let eventName = $state(rootEvent.name);
|
let eventName = $state(rootEvent.name);
|
||||||
let eventDeadline = $state(fromAbsolute(rootEvent.deadline, "Europe/Berlin"));
|
let eventDeadline = $state(fromAbsolute(rootEvent.deadline, "Europe/Berlin"));
|
||||||
@@ -45,13 +56,15 @@
|
|||||||
let eventSchematicType = $state(rootEvent.schemType);
|
let eventSchematicType = $state(rootEvent.schemType);
|
||||||
let eventPublicsOnly = $state(rootEvent.publicSchemsOnly);
|
let eventPublicsOnly = $state(rootEvent.publicSchemsOnly);
|
||||||
|
|
||||||
let dirty = $derived(eventName !== rootEvent.name ||
|
let dirty = $derived(
|
||||||
eventDeadline.toDate().getTime() !== rootEvent.deadline ||
|
eventName !== rootEvent.name ||
|
||||||
eventStart.toDate().getTime() !== rootEvent.start ||
|
eventDeadline.toDate().getTime() !== rootEvent.deadline ||
|
||||||
eventEnd.toDate().getTime() !== rootEvent.end ||
|
eventStart.toDate().getTime() !== rootEvent.start ||
|
||||||
eventTeamSize !== rootEvent.maxTeamMembers ||
|
eventEnd.toDate().getTime() !== rootEvent.end ||
|
||||||
eventSchematicType !== rootEvent.schemType ||
|
eventTeamSize !== rootEvent.maxTeamMembers ||
|
||||||
eventPublicsOnly !== rootEvent.publicSchemsOnly);
|
eventSchematicType !== rootEvent.schemType ||
|
||||||
|
eventPublicsOnly !== rootEvent.publicSchemsOnly
|
||||||
|
);
|
||||||
|
|
||||||
async function updateEvent() {
|
async function updateEvent() {
|
||||||
rootEvent = await $eventRepo.updateEvent(event.id.toString(), {
|
rootEvent = await $eventRepo.updateEvent(event.id.toString(), {
|
||||||
@@ -62,7 +75,7 @@
|
|||||||
maxTeamMembers: eventTeamSize,
|
maxTeamMembers: eventTeamSize,
|
||||||
schemType: eventSchematicType,
|
schemType: eventSchematicType,
|
||||||
publicSchemsOnly: eventPublicsOnly,
|
publicSchemsOnly: eventPublicsOnly,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -81,13 +94,8 @@
|
|||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
{#snippet child({ props })}
|
{#snippet child({ props })}
|
||||||
<Button
|
<Button variant="outline" class="justify-between" {...props} role="combobox">
|
||||||
variant="outline"
|
{$schemTypes.find((value) => value.db === eventSchematicType)?.name || eventSchematicType || "Select a schematic type..."}
|
||||||
class="justify-between"
|
|
||||||
{...props}
|
|
||||||
role="combobox"
|
|
||||||
>
|
|
||||||
{$schemTypes.find(value => value.db === eventSchematicType)?.name || eventSchematicType || "Select a schematic type..."}
|
|
||||||
<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
|
<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
|
||||||
</Button>
|
</Button>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
@@ -100,17 +108,12 @@
|
|||||||
<CommandGroup>
|
<CommandGroup>
|
||||||
{#each $schemTypes as type}
|
{#each $schemTypes as type}
|
||||||
<CommandItem
|
<CommandItem
|
||||||
value={type.db}
|
value={type.db}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
eventSchematicType = type.db;
|
eventSchematicType = type.db;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Check
|
<Check class={cn("mr-2 size-4", eventSchematicType !== type.db && "text-transparent")} />
|
||||||
class={cn(
|
|
||||||
"mr-2 size-4",
|
|
||||||
eventSchematicType !== type.db && "text-transparent"
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{type.name}
|
{type.name}
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -122,7 +125,19 @@
|
|||||||
<Label for="event-publics">Publics Schematics Only</Label>
|
<Label for="event-publics">Publics Schematics Only</Label>
|
||||||
<Switch id="event-publics" bind:checked={eventPublicsOnly} />
|
<Switch id="event-publics" bind:checked={eventPublicsOnly} />
|
||||||
<div class="flex flex-row justify-end border-t pt-2 gap-4">
|
<div class="flex flex-row justify-end border-t pt-2 gap-4">
|
||||||
<Button variant="destructive">Delete</Button>
|
<AlertDialog>
|
||||||
|
<AlertDialogTrigger class={buttonVariants({ variant: "destructive" })}>Delete</AlertDialogTrigger>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction disabled>Delete</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
<Button disabled={!dirty} onclick={updateEvent}>Update</Button>
|
<Button disabled={!dirty} onclick={updateEvent}>Update</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,26 +18,27 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {ExtendedEvent} from "@type/event";
|
import type { ExtendedEvent } from "@type/event";
|
||||||
import {createSvelteTable, FlexRender} from "@components/ui/data-table";
|
import { createSvelteTable, FlexRender } from "@components/ui/data-table";
|
||||||
import {
|
import { type ColumnFiltersState, getCoreRowModel, getFilteredRowModel, getGroupedRowModel, getSortedRowModel, type RowSelectionState, type SortingState } from "@tanstack/table-core";
|
||||||
type ColumnFiltersState,
|
import { columns } from "./columns";
|
||||||
getCoreRowModel, getFilteredRowModel,
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@components/ui/table";
|
||||||
getPaginationRowModel, getSortedRowModel,
|
import { Checkbox } from "@components/ui/checkbox";
|
||||||
type SortingState,
|
import { Menubar, MenubarContent, MenubarItem, MenubarGroup, MenubarGroupHeading, MenubarMenu, MenubarSeparator, MenubarTrigger } from "@components/ui/menubar";
|
||||||
} from "@tanstack/table-core";
|
|
||||||
import { columns } from "./columns"
|
|
||||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@components/ui/table";
|
|
||||||
|
|
||||||
let { data }: { data: ExtendedEvent } = $props();
|
let { data }: { data: ExtendedEvent } = $props();
|
||||||
|
|
||||||
let sorting = $state<SortingState>([]);
|
let sorting = $state<SortingState>([]);
|
||||||
let columnFilters = $state<ColumnFiltersState>([]);
|
let columnFilters = $state<ColumnFiltersState>([]);
|
||||||
|
let selection = $state<RowSelectionState>({});
|
||||||
|
|
||||||
const table = createSvelteTable({
|
const table = createSvelteTable({
|
||||||
get data() {
|
get data() {
|
||||||
return data.fights;
|
return data.fights;
|
||||||
},
|
},
|
||||||
|
initialState: {
|
||||||
|
columnOrder: ["auswahl", "begegnung", "group"],
|
||||||
|
},
|
||||||
state: {
|
state: {
|
||||||
get sorting() {
|
get sorting() {
|
||||||
return sorting;
|
return sorting;
|
||||||
@@ -45,6 +46,12 @@
|
|||||||
get columnFilters() {
|
get columnFilters() {
|
||||||
return columnFilters;
|
return columnFilters;
|
||||||
},
|
},
|
||||||
|
get grouping() {
|
||||||
|
return ["group"];
|
||||||
|
},
|
||||||
|
get rowSelection() {
|
||||||
|
return selection;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
onSortingChange: (updater) => {
|
onSortingChange: (updater) => {
|
||||||
if (typeof updater === "function") {
|
if (typeof updater === "function") {
|
||||||
@@ -60,13 +67,47 @@
|
|||||||
columnFilters = updater;
|
columnFilters = updater;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onRowSelectionChange: (updater) => {
|
||||||
|
if (typeof updater === "function") {
|
||||||
|
selection = updater(selection);
|
||||||
|
} else {
|
||||||
|
selection = updater;
|
||||||
|
}
|
||||||
|
},
|
||||||
columns,
|
columns,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getFilteredRowModel: getFilteredRowModel(),
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getGroupedRowModel: getGroupedRowModel(),
|
||||||
|
groupedColumnMode: "remove",
|
||||||
|
getRowId: (row) => row.id.toString(),
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="w-fit">
|
||||||
|
<Menubar>
|
||||||
|
<MenubarMenu>
|
||||||
|
<MenubarTrigger>Mehrfach Bearbeiten</MenubarTrigger>
|
||||||
|
<MenubarContent>
|
||||||
|
<MenubarItem disabled>Gruppe Ändern</MenubarItem>
|
||||||
|
<MenubarItem disabled>Startzeit Verschieben</MenubarItem>
|
||||||
|
<MenubarItem disabled>Spectate Port Ändern</MenubarItem>
|
||||||
|
</MenubarContent>
|
||||||
|
</MenubarMenu>
|
||||||
|
<MenubarMenu>
|
||||||
|
<MenubarTrigger>Erstellen</MenubarTrigger>
|
||||||
|
<MenubarContent>
|
||||||
|
<MenubarItem disabled>Fight Erstellen</MenubarItem>
|
||||||
|
<MenubarGroup>
|
||||||
|
<MenubarGroupHeading>Generatoren</MenubarGroupHeading>
|
||||||
|
<MenubarItem disabled>Gruppenphase</MenubarItem>
|
||||||
|
<MenubarItem disabled>K.O. Phase</MenubarItem>
|
||||||
|
</MenubarGroup>
|
||||||
|
</MenubarContent>
|
||||||
|
</MenubarMenu>
|
||||||
|
</Menubar>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
||||||
@@ -74,10 +115,7 @@
|
|||||||
{#each headerGroup.headers as header (header.id)}
|
{#each headerGroup.headers as header (header.id)}
|
||||||
<TableHead>
|
<TableHead>
|
||||||
{#if !header.isPlaceholder}
|
{#if !header.isPlaceholder}
|
||||||
<FlexRender
|
<FlexRender content={header.column.columnDef.header} context={header.getContext()} />
|
||||||
content={header.column.columnDef.header}
|
|
||||||
context={header.getContext()}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
</TableHead>
|
</TableHead>
|
||||||
{/each}
|
{/each}
|
||||||
@@ -85,23 +123,41 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{#each table.getRowModel().rows as row (row.id)}
|
{#each table.getRowModel().rows as groupRow (groupRow.id)}
|
||||||
<TableRow data-state={row.getIsSelected() && "selected"}>
|
{#if groupRow.getIsGrouped()}
|
||||||
{#each row.getVisibleCells() as cell (cell.id)}
|
<TableRow class="bg-muted font-bold">
|
||||||
<TableCell>
|
<TableCell colspan={columns.length}>
|
||||||
<FlexRender
|
<Checkbox
|
||||||
content={cell.column.columnDef.cell}
|
checked={groupRow.getIsSelected()}
|
||||||
context={cell.getContext()}
|
indeterminate={groupRow.getIsSomeSelected() && !groupRow.getIsSelected()}
|
||||||
|
onCheckedChange={() => groupRow.toggleSelected()}
|
||||||
|
class="mr-4"
|
||||||
/>
|
/>
|
||||||
|
Gruppe: {groupRow.getValue("group") ?? "Keine"}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
{#each groupRow.subRows as row (row.id)}
|
||||||
|
<TableRow data-state={row.getIsSelected() && "selected"}>
|
||||||
|
{#each row.getVisibleCells() as cell (cell.id)}
|
||||||
|
<TableCell>
|
||||||
|
<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
|
||||||
|
</TableCell>
|
||||||
|
{/each}
|
||||||
|
</TableRow>
|
||||||
{/each}
|
{/each}
|
||||||
</TableRow>
|
{:else}
|
||||||
|
<TableRow data-state={groupRow.getIsSelected() && "selected"}>
|
||||||
|
{#each groupRow.getVisibleCells() as cell (cell.id)}
|
||||||
|
<TableCell>
|
||||||
|
<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
|
||||||
|
</TableCell>
|
||||||
|
{/each}
|
||||||
|
</TableRow>
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colspan={columns.length} class="h-24 text-center">
|
<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
|
||||||
No results.
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{/each}
|
{/each}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|||||||
@@ -18,14 +18,13 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {ExtendedEvent} from "@type/event.ts";
|
import type { ExtendedEvent } from "@type/event.ts";
|
||||||
import EventEdit from "@components/moderator/pages/event/EventEdit.svelte";
|
import EventEdit from "@components/moderator/pages/event/EventEdit.svelte";
|
||||||
import EventFightList from "@components/moderator/pages/event/EventFightList.svelte";
|
import EventFightList from "@components/moderator/pages/event/EventFightList.svelte";
|
||||||
import RefereesList from "@components/moderator/pages/event/RefereesList.svelte";
|
import RefereesList from "@components/moderator/pages/event/RefereesList.svelte";
|
||||||
|
import TeamTable from "@components/moderator/pages/event/TeamTable.svelte";
|
||||||
|
|
||||||
const {
|
const { event }: { event: ExtendedEvent } = $props();
|
||||||
event
|
|
||||||
}: { event: ExtendedEvent } = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-col m-4 p-4 rounded-md border gap-4">
|
<div class="flex flex-col m-4 p-4 rounded-md border gap-4">
|
||||||
@@ -35,12 +34,12 @@
|
|||||||
<EventEdit event={event.event} />
|
<EventEdit event={event.event} />
|
||||||
</div>
|
</div>
|
||||||
<div class="md:ml-4 md:pl-4 md:border-l md:w-1/3">
|
<div class="md:ml-4 md:pl-4 md:border-l md:w-1/3">
|
||||||
<h2>Teams</h2>
|
<h2 class="text-xl font-bold mb-4">Teams</h2>
|
||||||
|
<TeamTable {event} />
|
||||||
</div>
|
</div>
|
||||||
<div class="md:ml-4 md:pl-4 md:border-l md:w-1/3">
|
<div class="md:ml-4 md:pl-4 md:border-l md:w-1/3">
|
||||||
<h2>Referees</h2>
|
<h2 class="text-xl font-bold mb-4">Referees</h2>
|
||||||
<RefereesList event={event} />
|
<RefereesList {event} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<EventFightList data={event} />
|
<EventFightList data={event} />
|
||||||
|
|||||||
@@ -18,38 +18,35 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from "@components/ui/table/index.js";
|
import { Table, TableBody, TableCell, TableCaption, TableHead, TableHeader, TableRow } from "@components/ui/table";
|
||||||
import {
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@components/ui/command/index.js";
|
||||||
Command,
|
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover/index.js";
|
||||||
CommandEmpty,
|
import { Button } from "@components/ui/button/index.js";
|
||||||
CommandGroup,
|
import type { ExtendedEvent } from "@type/event.ts";
|
||||||
CommandInput,
|
|
||||||
CommandItem,
|
|
||||||
CommandList,
|
|
||||||
} from "@components/ui/command/index.js";
|
|
||||||
import {Popover, PopoverContent, PopoverTrigger} from "@components/ui/popover/index.js";
|
|
||||||
import {Button} from "@components/ui/button/index.js";
|
|
||||||
import type {ExtendedEvent} from "@type/event.ts";
|
|
||||||
import { eventRepo } from "@repo/event";
|
import { eventRepo } from "@repo/event";
|
||||||
import { players } from "@stores/stores"
|
import { players } from "@stores/stores";
|
||||||
|
|
||||||
const {
|
const { event }: { event: ExtendedEvent } = $props();
|
||||||
event
|
|
||||||
}: { event: ExtendedEvent } = $props();
|
|
||||||
|
|
||||||
let referees = $state(event.event.referees)
|
let referees = $state(event.event.referees);
|
||||||
|
|
||||||
async function addReferee(value: string) {
|
async function addReferee(value: string) {
|
||||||
referees = (await $eventRepo.updateEvent(event.event.id.toString(), {
|
referees = (
|
||||||
addReferee: [value]
|
await $eventRepo.updateEvent(event.event.id.toString(), {
|
||||||
})).referees;
|
addReferee: [value],
|
||||||
|
})
|
||||||
|
).referees;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeReferee(value: string) {
|
async function removeReferee(value: string) {
|
||||||
referees = (await $eventRepo.updateEvent(event.event.id.toString(), {
|
referees = (
|
||||||
removeReferee: [value]
|
await $eventRepo.updateEvent(event.event.id.toString(), {
|
||||||
})).referees;
|
removeReferee: [value],
|
||||||
|
})
|
||||||
|
).referees;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let playerSearch = $state("");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Table>
|
<Table>
|
||||||
@@ -69,24 +66,27 @@
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
{/each}
|
{/each}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
<Popover>
|
||||||
|
<TableCaption>
|
||||||
|
<PopoverTrigger>
|
||||||
|
<Button>Add</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
</TableCaption>
|
||||||
|
<PopoverContent class="p-0">
|
||||||
|
<Command shouldFilter={false}>
|
||||||
|
<CommandInput bind:value={playerSearch} placeholder="Search players..." />
|
||||||
|
<CommandList>
|
||||||
|
<CommandEmpty>No Players found :(</CommandEmpty>
|
||||||
|
<CommandGroup heading="Players">
|
||||||
|
{#each $players
|
||||||
|
.filter((v) => v.name.includes(playerSearch))
|
||||||
|
.filter((v, i) => i < 50)
|
||||||
|
.filter((v) => !referees.some((k) => k.uuid === v.uuid)) as player (player.uuid)}
|
||||||
|
<CommandItem value={player.name} onSelect={() => addReferee(player.uuid)} keywords={[player.uuid]}>{player.name}</CommandItem>
|
||||||
|
{/each}
|
||||||
|
</CommandGroup>
|
||||||
|
</CommandList>
|
||||||
|
</Command>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
</Table>
|
</Table>
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger>
|
|
||||||
<Button>
|
|
||||||
Add
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent class="p-0">
|
|
||||||
<Command>
|
|
||||||
<CommandInput placeholder="Search players..." />
|
|
||||||
<CommandList>
|
|
||||||
<CommandEmpty>No Players found :(</CommandEmpty>
|
|
||||||
<CommandGroup heading="Players">
|
|
||||||
{#each $players.filter(v => v.perms.length > 0).filter(v => !referees.some(k => k.uuid === v.uuid)) as player (player.uuid)}
|
|
||||||
<CommandItem value={player.uuid} onSelect={() => addReferee(player.uuid)}>{player.name}</CommandItem>
|
|
||||||
{/each}
|
|
||||||
</CommandGroup>
|
|
||||||
</CommandList>
|
|
||||||
</Command>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
55
src/components/moderator/pages/event/TeamTable.svelte
Normal file
55
src/components/moderator/pages/event/TeamTable.svelte
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<!--
|
||||||
|
- This file is a part of the SteamWar software.
|
||||||
|
-
|
||||||
|
- Copyright (C) 2025 SteamWar.de-Serverteam
|
||||||
|
-
|
||||||
|
- This program is free software: you can redistribute it and/or modify
|
||||||
|
- it under the terms of the GNU Affero General Public License as published by
|
||||||
|
- the Free Software Foundation, either version 3 of the License, or
|
||||||
|
- (at your option) any later version.
|
||||||
|
-
|
||||||
|
- This program is distributed in the hope that it will be useful,
|
||||||
|
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
- GNU Affero General Public License for more details.
|
||||||
|
-
|
||||||
|
- You should have received a copy of the GNU Affero General Public License
|
||||||
|
- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Button } from "@components/ui/button";
|
||||||
|
import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell, TableCaption } from "@components/ui/table";
|
||||||
|
import type { ExtendedEvent } from "@type/event.ts";
|
||||||
|
|
||||||
|
const { event }: { event: ExtendedEvent } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Table>
|
||||||
|
<TableCaption>
|
||||||
|
<Button disabled>Add Team</Button>
|
||||||
|
</TableCaption>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead>Team</TableHead>
|
||||||
|
<TableHead>Name</TableHead>
|
||||||
|
<TableHead>Action</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{#each event.teams as team (team.id)}
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>{team.kuerzel}</TableCell>
|
||||||
|
<TableCell>{team.name}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button disabled>Remove</Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
{/each}
|
||||||
|
{#if event.teams.length === 0}
|
||||||
|
<TableRow>
|
||||||
|
<TableCell class="text-center col-span-3">No teams available</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
{/if}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
@@ -17,16 +17,64 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {ColumnDef} from "@tanstack/table-core";
|
import { Checkbox } from "@components/ui/checkbox";
|
||||||
import type {EventFight} from "@type/event.ts";
|
import { renderComponent } from "@components/ui/data-table";
|
||||||
|
import type { ColumnDef } from "@tanstack/table-core";
|
||||||
|
import type { EventFight } from "@type/event.ts";
|
||||||
|
|
||||||
export const columns: ColumnDef<EventFight> = [
|
export const columns: ColumnDef<EventFight> = [
|
||||||
{
|
{
|
||||||
accessorFn: (r) => r.blueTeam.name,
|
id: "auswahl",
|
||||||
header: "Team Blue",
|
header: ({ table }) => {
|
||||||
|
return renderComponent(Checkbox, {
|
||||||
|
checked: table.getIsAllRowsSelected(),
|
||||||
|
indeterminate: table.getIsSomeRowsSelected(),
|
||||||
|
onCheckedChange: () => {
|
||||||
|
if (!table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()) {
|
||||||
|
const now = new Date();
|
||||||
|
const rows = table.getRowModel().rows.filter((row) => new Date(row.original.date) > now);
|
||||||
|
|
||||||
|
if (rows.length > 0) {
|
||||||
|
rows.forEach((row) => {
|
||||||
|
row.toggleSelected();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
table.toggleAllRowsSelected(true);
|
||||||
|
}
|
||||||
|
} else if (table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()) {
|
||||||
|
table.toggleAllRowsSelected(true);
|
||||||
|
} else {
|
||||||
|
table.toggleAllRowsSelected(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return renderComponent(Checkbox, {
|
||||||
|
checked: row.getIsSelected(),
|
||||||
|
onCheckedChange: row.getToggleSelectedHandler(),
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorFn: (r) => r.redTeam.name,
|
accessorFn: (r) => r.blueTeam.name + " vs " + r.redTeam.name,
|
||||||
header: "Team Red",
|
id: "begegnung",
|
||||||
|
header: "Begegnung",
|
||||||
},
|
},
|
||||||
];
|
{
|
||||||
|
header: "Gruppe",
|
||||||
|
accessorKey: "group",
|
||||||
|
id: "group",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Datum",
|
||||||
|
accessorKey: "start",
|
||||||
|
id: "start",
|
||||||
|
cell: ({ row }) => {
|
||||||
|
return new Date(row.getValue("start")).toLocaleString("de-DE", {
|
||||||
|
dateStyle: "short",
|
||||||
|
timeStyle: "medium",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|||||||
@@ -3,19 +3,11 @@
|
|||||||
import { buttonVariants } from "$lib/components/ui/button/index.js";
|
import { buttonVariants } from "$lib/components/ui/button/index.js";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = AlertDialogPrimitive.ActionProps;
|
let {
|
||||||
type $$Events = AlertDialogPrimitive.ActionEvents;
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
let className: $$Props["class"] = undefined;
|
...restProps
|
||||||
export { className as class };
|
}: AlertDialogPrimitive.ActionProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AlertDialogPrimitive.Action
|
<AlertDialogPrimitive.Action bind:ref class={cn(buttonVariants(), className)} {...restProps} />
|
||||||
class={cn(buttonVariants(), className)}
|
|
||||||
{...$$restProps}
|
|
||||||
on:click
|
|
||||||
on:keydown
|
|
||||||
let:builder
|
|
||||||
>
|
|
||||||
<slot {builder} />
|
|
||||||
</AlertDialogPrimitive.Action>
|
|
||||||
|
|||||||
@@ -3,19 +3,15 @@
|
|||||||
import { buttonVariants } from "$lib/components/ui/button/index.js";
|
import { buttonVariants } from "$lib/components/ui/button/index.js";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = AlertDialogPrimitive.CancelProps;
|
let {
|
||||||
type $$Events = AlertDialogPrimitive.CancelEvents;
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
let className: $$Props["class"] = undefined;
|
...restProps
|
||||||
export { className as class };
|
}: AlertDialogPrimitive.CancelProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AlertDialogPrimitive.Cancel
|
<AlertDialogPrimitive.Cancel
|
||||||
|
bind:ref
|
||||||
class={cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className)}
|
class={cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
on:click
|
/>
|
||||||
on:keydown
|
|
||||||
let:builder
|
|
||||||
>
|
|
||||||
<slot {builder} />
|
|
||||||
</AlertDialogPrimitive.Cancel>
|
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
import { AlertDialog as AlertDialogPrimitive, type WithoutChild } from "bits-ui";
|
||||||
import * as AlertDialog from "./index.js";
|
import AlertDialogOverlay from "./alert-dialog-overlay.svelte";
|
||||||
import { cn, flyAndScale } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = AlertDialogPrimitive.ContentProps;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
export let transition: $$Props["transition"] = flyAndScale;
|
class: className,
|
||||||
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
portalProps,
|
||||||
|
...restProps
|
||||||
let className: $$Props["class"] = undefined;
|
}: WithoutChild<AlertDialogPrimitive.ContentProps> & {
|
||||||
export { className as class };
|
portalProps?: AlertDialogPrimitive.PortalProps;
|
||||||
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AlertDialog.Portal>
|
<AlertDialogPrimitive.Portal {...portalProps}>
|
||||||
<AlertDialog.Overlay />
|
<AlertDialogOverlay />
|
||||||
<AlertDialogPrimitive.Content
|
<AlertDialogPrimitive.Content
|
||||||
{transition}
|
bind:ref
|
||||||
{transitionConfig}
|
|
||||||
class={cn(
|
class={cn(
|
||||||
"bg-background fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg sm:rounded-lg md:w-full",
|
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
>
|
/>
|
||||||
<slot />
|
</AlertDialogPrimitive.Portal>
|
||||||
</AlertDialogPrimitive.Content>
|
|
||||||
</AlertDialog.Portal>
|
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = AlertDialogPrimitive.DescriptionProps;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export { className as class };
|
...restProps
|
||||||
|
}: AlertDialogPrimitive.DescriptionProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AlertDialogPrimitive.Description
|
<AlertDialogPrimitive.Description
|
||||||
|
bind:ref
|
||||||
class={cn("text-muted-foreground text-sm", className)}
|
class={cn("text-muted-foreground text-sm", className)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
>
|
/>
|
||||||
<slot />
|
|
||||||
</AlertDialogPrimitive.Description>
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { WithElementRef } from "bits-ui";
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export { className as class };
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
bind:this={ref}
|
||||||
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<slot />
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { WithElementRef } from "bits-ui";
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export { className as class };
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...$$restProps}>
|
<div
|
||||||
<slot />
|
bind:this={ref}
|
||||||
|
class={cn("flex flex-col space-y-2 text-center sm:text-left", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,21 +1,19 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
||||||
import { fade } from "svelte/transition";
|
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = AlertDialogPrimitive.OverlayProps;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export let transition: $$Props["transition"] = fade;
|
...restProps
|
||||||
export let transitionConfig: $$Props["transitionConfig"] = {
|
}: AlertDialogPrimitive.OverlayProps = $props();
|
||||||
duration: 150,
|
|
||||||
};
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AlertDialogPrimitive.Overlay
|
<AlertDialogPrimitive.Overlay
|
||||||
{transition}
|
bind:ref
|
||||||
{transitionConfig}
|
class={cn(
|
||||||
class={cn("bg-background/80 fixed inset-0 z-50 backdrop-blur-sm ", className)}
|
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
|
||||||
{...$$restProps}
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,13 +2,17 @@
|
|||||||
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = AlertDialogPrimitive.TitleProps;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export let level: $$Props["level"] = "h3";
|
level = 3,
|
||||||
export { className as class };
|
...restProps
|
||||||
|
}: AlertDialogPrimitive.TitleProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AlertDialogPrimitive.Title class={cn("text-lg font-semibold", className)} {level} {...$$restProps}>
|
<AlertDialogPrimitive.Title
|
||||||
<slot />
|
bind:ref
|
||||||
</AlertDialogPrimitive.Title>
|
class={cn("text-lg font-semibold", className)}
|
||||||
|
{level}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
import { AlertDialog as AlertDialogPrimitive } from "bits-ui";
|
||||||
|
|
||||||
import Title from "./alert-dialog-title.svelte";
|
import Title from "./alert-dialog-title.svelte";
|
||||||
import Action from "./alert-dialog-action.svelte";
|
import Action from "./alert-dialog-action.svelte";
|
||||||
import Cancel from "./alert-dialog-cancel.svelte";
|
import Cancel from "./alert-dialog-cancel.svelte";
|
||||||
import Portal from "./alert-dialog-portal.svelte";
|
|
||||||
import Footer from "./alert-dialog-footer.svelte";
|
import Footer from "./alert-dialog-footer.svelte";
|
||||||
import Header from "./alert-dialog-header.svelte";
|
import Header from "./alert-dialog-header.svelte";
|
||||||
import Overlay from "./alert-dialog-overlay.svelte";
|
import Overlay from "./alert-dialog-overlay.svelte";
|
||||||
@@ -12,6 +10,7 @@ import Description from "./alert-dialog-description.svelte";
|
|||||||
|
|
||||||
const Root = AlertDialogPrimitive.Root;
|
const Root = AlertDialogPrimitive.Root;
|
||||||
const Trigger = AlertDialogPrimitive.Trigger;
|
const Trigger = AlertDialogPrimitive.Trigger;
|
||||||
|
const Portal = AlertDialogPrimitive.Portal;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Checkbox as CheckboxPrimitive } from "bits-ui";
|
import { Checkbox as CheckboxPrimitive, type WithoutChildrenOrChild } from "bits-ui";
|
||||||
import Check from "lucide-svelte/icons/check";
|
import Check from "@lucide/svelte/icons/check";
|
||||||
import Minus from "lucide-svelte/icons/minus";
|
import Minus from "@lucide/svelte/icons/minus";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = CheckboxPrimitive.Props;
|
let {
|
||||||
type $$Events = CheckboxPrimitive.Events;
|
ref = $bindable(null),
|
||||||
|
checked = $bindable(false),
|
||||||
let className: $$Props["class"] = undefined;
|
indeterminate = $bindable(false),
|
||||||
export let checked: $$Props["checked"] = false;
|
class: className,
|
||||||
export { className as class };
|
...restProps
|
||||||
|
}: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
"border-primary ring-offset-background focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground peer box-content h-4 w-4 shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
|
"border-primary ring-offset-background focus-visible:ring-ring data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground peer box-content size-4 shrink-0 rounded-sm border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
bind:checked
|
bind:checked
|
||||||
{...$$restProps}
|
bind:indeterminate
|
||||||
on:click
|
{...restProps}
|
||||||
>
|
>
|
||||||
<CheckboxPrimitive.Indicator
|
{#snippet children({ checked, indeterminate })}
|
||||||
class={cn("flex h-4 w-4 items-center justify-center text-current")}
|
<div class="flex size-4 items-center justify-center text-current">
|
||||||
let:isChecked
|
{#if indeterminate}
|
||||||
let:isIndeterminate
|
<Minus class="size-3.5" />
|
||||||
>
|
{:else}
|
||||||
{#if isChecked}
|
<Check class={cn("size-3.5", !checked && "text-transparent")} />
|
||||||
<Check class="h-3.5 w-3.5" />
|
{/if}
|
||||||
{:else if isIndeterminate}
|
</div>
|
||||||
<Minus class="h-3.5 w-3.5" />
|
{/snippet}
|
||||||
{/if}
|
|
||||||
</CheckboxPrimitive.Indicator>
|
|
||||||
</CheckboxPrimitive.Root>
|
</CheckboxPrimitive.Root>
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
|
||||||
import Root from "./menubar.svelte";
|
import Root from "./menubar.svelte";
|
||||||
import CheckboxItem from "./menubar-checkbox-item.svelte";
|
import CheckboxItem from "./menubar-checkbox-item.svelte";
|
||||||
import Content from "./menubar-content.svelte";
|
import Content from "./menubar-content.svelte";
|
||||||
import Item from "./menubar-item.svelte";
|
import Item from "./menubar-item.svelte";
|
||||||
import Label from "./menubar-label.svelte";
|
import GroupHeading from "./menubar-group-heading.svelte";
|
||||||
import RadioItem from "./menubar-radio-item.svelte";
|
import RadioItem from "./menubar-radio-item.svelte";
|
||||||
import Separator from "./menubar-separator.svelte";
|
import Separator from "./menubar-separator.svelte";
|
||||||
import Shortcut from "./menubar-shortcut.svelte";
|
import Shortcut from "./menubar-shortcut.svelte";
|
||||||
@@ -22,7 +21,7 @@ export {
|
|||||||
CheckboxItem,
|
CheckboxItem,
|
||||||
Content,
|
Content,
|
||||||
Item,
|
Item,
|
||||||
Label,
|
GroupHeading,
|
||||||
RadioItem,
|
RadioItem,
|
||||||
Separator,
|
Separator,
|
||||||
Shortcut,
|
Shortcut,
|
||||||
@@ -38,7 +37,7 @@ export {
|
|||||||
CheckboxItem as MenubarCheckboxItem,
|
CheckboxItem as MenubarCheckboxItem,
|
||||||
Content as MenubarContent,
|
Content as MenubarContent,
|
||||||
Item as MenubarItem,
|
Item as MenubarItem,
|
||||||
Label as MenubarLabel,
|
GroupHeading as MenubarGroupHeading,
|
||||||
RadioItem as MenubarRadioItem,
|
RadioItem as MenubarRadioItem,
|
||||||
Separator as MenubarSeparator,
|
Separator as MenubarSeparator,
|
||||||
Shortcut as MenubarShortcut,
|
Shortcut as MenubarShortcut,
|
||||||
|
|||||||
@@ -1,35 +1,40 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive, type WithoutChildrenOrChild } from "bits-ui";
|
||||||
import Check from "lucide-svelte/icons/check";
|
import Check from "@lucide/svelte/icons/check";
|
||||||
|
import Minus from "@lucide/svelte/icons/minus";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
import type { Snippet } from "svelte";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.CheckboxItemProps;
|
let {
|
||||||
type $$Events = MenubarPrimitive.CheckboxItemEvents;
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
let className: $$Props["class"] = undefined;
|
checked = $bindable(false),
|
||||||
export let checked: $$Props["checked"] = false;
|
indeterminate = $bindable(false),
|
||||||
export { className as class };
|
children: childrenProp,
|
||||||
|
...restProps
|
||||||
|
}: WithoutChildrenOrChild<MenubarPrimitive.CheckboxItemProps> & {
|
||||||
|
children?: Snippet;
|
||||||
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.CheckboxItem
|
<MenubarPrimitive.CheckboxItem
|
||||||
|
bind:ref
|
||||||
bind:checked
|
bind:checked
|
||||||
|
bind:indeterminate
|
||||||
class={cn(
|
class={cn(
|
||||||
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
on:click
|
{...restProps}
|
||||||
on:keydown
|
|
||||||
on:focusin
|
|
||||||
on:focusout
|
|
||||||
on:pointerleave
|
|
||||||
on:pointermove
|
|
||||||
on:pointerdown
|
|
||||||
{...$$restProps}
|
|
||||||
>
|
>
|
||||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
{#snippet children({ checked, indeterminate })}
|
||||||
<MenubarPrimitive.CheckboxIndicator>
|
<span class="absolute left-2 flex size-3.5 items-center justify-center">
|
||||||
<Check class="h-4 w-4" />
|
{#if indeterminate}
|
||||||
</MenubarPrimitive.CheckboxIndicator>
|
<Minus class="size-4" />
|
||||||
</span>
|
{:else}
|
||||||
<slot />
|
<Check class={cn("size-4", !checked && "text-transparent")} />
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
{@render childrenProp?.()}
|
||||||
|
{/snippet}
|
||||||
</MenubarPrimitive.CheckboxItem>
|
</MenubarPrimitive.CheckboxItem>
|
||||||
|
|||||||
@@ -1,33 +1,32 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
import { cn, flyAndScale } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.ContentProps;
|
let {
|
||||||
type $$Events = MenubarPrimitive.ContentEvents;
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
let className: $$Props["class"] = undefined;
|
sideOffset = 8,
|
||||||
export let sideOffset: $$Props["sideOffset"] = 8;
|
alignOffset = -4,
|
||||||
export let alignOffset: $$Props["alignOffset"] = -4;
|
align = "start",
|
||||||
export let align: $$Props["align"] = "start";
|
side = "bottom",
|
||||||
export let side: $$Props["side"] = "bottom";
|
portalProps,
|
||||||
export let transition: $$Props["transition"] = flyAndScale;
|
...restProps
|
||||||
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
}: MenubarPrimitive.ContentProps & {
|
||||||
export { className as class };
|
portalProps?: MenubarPrimitive.PortalProps;
|
||||||
|
} = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.Content
|
<MenubarPrimitive.Portal {...portalProps}>
|
||||||
{transition}
|
<MenubarPrimitive.Content
|
||||||
{transitionConfig}
|
bind:ref
|
||||||
{sideOffset}
|
{sideOffset}
|
||||||
{align}
|
{align}
|
||||||
{alignOffset}
|
{alignOffset}
|
||||||
{side}
|
{side}
|
||||||
class={cn(
|
class={cn(
|
||||||
"bg-popover text-popover-foreground z-50 min-w-[12rem] rounded-md border p-1 shadow-md focus:outline-none",
|
"bg-popover text-popover-foreground z-50 min-w-[12rem] rounded-md border p-1 shadow-md focus:outline-none",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
on:keydown
|
/>
|
||||||
>
|
</MenubarPrimitive.Portal>
|
||||||
<slot />
|
|
||||||
</MenubarPrimitive.Content>
|
|
||||||
|
|||||||
19
src/components/ui/menubar/menubar-group-heading.svelte
Normal file
19
src/components/ui/menubar/menubar-group-heading.svelte
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
inset = undefined,
|
||||||
|
...restProps
|
||||||
|
}: MenubarPrimitive.GroupHeadingProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<MenubarPrimitive.GroupHeading
|
||||||
|
bind:ref
|
||||||
|
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
@@ -2,30 +2,22 @@
|
|||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.ItemProps & {
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
inset = undefined,
|
||||||
|
...restProps
|
||||||
|
}: MenubarPrimitive.ItemProps & {
|
||||||
inset?: boolean;
|
inset?: boolean;
|
||||||
};
|
} = $props();
|
||||||
type $$Events = MenubarPrimitive.ItemEvents;
|
|
||||||
|
|
||||||
let className: $$Props["class"] = undefined;
|
|
||||||
export let inset: $$Props["inset"] = undefined;
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.Item
|
<MenubarPrimitive.Item
|
||||||
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
on:click
|
/>
|
||||||
on:keydown
|
|
||||||
on:focusin
|
|
||||||
on:focusout
|
|
||||||
on:pointerleave
|
|
||||||
on:pointermove
|
|
||||||
on:pointerdown
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</MenubarPrimitive.Item>
|
|
||||||
|
|||||||
@@ -1,35 +1,30 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive, type WithoutChild } from "bits-ui";
|
||||||
import Circle from "lucide-svelte/icons/circle";
|
import Circle from "@lucide/svelte/icons/circle";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.RadioItemProps;
|
let {
|
||||||
type $$Events = MenubarPrimitive.RadioItemEvents;
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
let className: $$Props["class"] = undefined;
|
children: childrenProp,
|
||||||
export let value: $$Props["value"];
|
...restProps
|
||||||
export { className as class };
|
}: WithoutChild<MenubarPrimitive.RadioItemProps> = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.RadioItem
|
<MenubarPrimitive.RadioItem
|
||||||
{value}
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
on:click
|
|
||||||
on:keydown
|
|
||||||
on:focusin
|
|
||||||
on:focusout
|
|
||||||
on:pointerleave
|
|
||||||
on:pointermove
|
|
||||||
on:pointerdown
|
|
||||||
>
|
>
|
||||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
{#snippet children({ checked })}
|
||||||
<MenubarPrimitive.RadioIndicator>
|
<span class="absolute left-2 flex size-3.5 items-center justify-center">
|
||||||
<Circle class="h-2 w-2 fill-current" />
|
{#if checked}
|
||||||
</MenubarPrimitive.RadioIndicator>
|
<Circle class="size-2 fill-current" />
|
||||||
</span>
|
{/if}
|
||||||
<slot />
|
</span>
|
||||||
|
{@render childrenProp?.({ checked })}
|
||||||
|
{/snippet}
|
||||||
</MenubarPrimitive.RadioItem>
|
</MenubarPrimitive.RadioItem>
|
||||||
|
|||||||
@@ -2,10 +2,15 @@
|
|||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.SeparatorProps;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export { className as class };
|
...restProps
|
||||||
|
}: MenubarPrimitive.SeparatorProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.Separator class={cn("bg-muted -mx-1 my-1 h-px", className)} {...$$restProps} />
|
<MenubarPrimitive.Separator
|
||||||
|
bind:ref
|
||||||
|
class={cn("bg-muted -mx-1 my-1 h-px", className)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import type { WithElementRef } from "bits-ui";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export { className as class };
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLSpanElement>> = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
|
bind:this={ref}
|
||||||
class={cn("text-muted-foreground ml-auto text-xs tracking-widest", className)}
|
class={cn("text-muted-foreground ml-auto text-xs tracking-widest", className)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
<slot />
|
{@render children?.()}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,27 +1,19 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
import { cn, flyAndScale } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.SubContentProps;
|
let {
|
||||||
type $$Events = MenubarPrimitive.SubContentEvents;
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
let className: $$Props["class"] = undefined;
|
...restProps
|
||||||
export let transition: $$Props["transition"] = flyAndScale;
|
}: MenubarPrimitive.SubContentProps = $props();
|
||||||
export let transitionConfig: $$Props["transitionConfig"] = { x: -10, y: 0 };
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.SubContent
|
<MenubarPrimitive.SubContent
|
||||||
{transition}
|
bind:ref
|
||||||
{transitionConfig}
|
|
||||||
class={cn(
|
class={cn(
|
||||||
"bg-popover text-popover-foreground z-50 min-w-max rounded-md border p-1 focus:outline-none",
|
"bg-popover text-popover-foreground z-50 min-w-max rounded-md border p-1 focus:outline-none",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
on:focusout
|
/>
|
||||||
on:pointermove
|
|
||||||
on:keydown
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</MenubarPrimitive.SubContent>
|
|
||||||
|
|||||||
@@ -1,32 +1,28 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive, type WithoutChild } from "bits-ui";
|
||||||
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
import ChevronRight from "@lucide/svelte/icons/chevron-right";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.SubTriggerProps & {
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
inset = undefined,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithoutChild<MenubarPrimitive.SubTriggerProps> & {
|
||||||
inset?: boolean;
|
inset?: boolean;
|
||||||
};
|
} = $props();
|
||||||
type $$Events = MenubarPrimitive.SubTriggerEvents;
|
|
||||||
|
|
||||||
let className: $$Props["class"] = undefined;
|
|
||||||
export let inset: $$Props["inset"] = undefined;
|
|
||||||
export { className as class };
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.SubTrigger
|
<MenubarPrimitive.SubTrigger
|
||||||
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
"data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
inset && "pl-8",
|
inset && "pl-8",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
on:click
|
{...restProps}
|
||||||
{...$$restProps}
|
|
||||||
on:keydown
|
|
||||||
on:focusin
|
|
||||||
on:focusout
|
|
||||||
on:pointerleave
|
|
||||||
on:pointermove
|
|
||||||
>
|
>
|
||||||
<slot />
|
{@render children?.()}
|
||||||
<ChevronRight class="ml-auto h-4 w-4" />
|
<ChevronRight class="ml-auto size-4" />
|
||||||
</MenubarPrimitive.SubTrigger>
|
</MenubarPrimitive.SubTrigger>
|
||||||
|
|||||||
@@ -2,22 +2,18 @@
|
|||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.TriggerProps;
|
let {
|
||||||
type $$Events = MenubarPrimitive.TriggerEvents;
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
let className: $$Props["class"] = undefined;
|
...restProps
|
||||||
export { className as class };
|
}: MenubarPrimitive.TriggerProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.Trigger
|
<MenubarPrimitive.Trigger
|
||||||
|
bind:ref
|
||||||
class={cn(
|
class={cn(
|
||||||
"data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none",
|
"data-[highlighted]:bg-accent data-[state=open]:bg-accent data-[highlighted]:text-accent-foreground data-[state=open]:text-accent-foreground flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
on:click
|
{...restProps}
|
||||||
on:keydown
|
/>
|
||||||
on:pointerenter
|
|
||||||
{...$$restProps}
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</MenubarPrimitive.Trigger>
|
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
import { Menubar as MenubarPrimitive } from "bits-ui";
|
import { Menubar as MenubarPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/components/utils.js";
|
import { cn } from "$lib/components/utils.js";
|
||||||
|
|
||||||
type $$Props = MenubarPrimitive.Props;
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
let className: $$Props["class"] = undefined;
|
class: className,
|
||||||
export { className as class };
|
...restProps
|
||||||
|
}: MenubarPrimitive.RootProps = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<MenubarPrimitive.Root
|
<MenubarPrimitive.Root
|
||||||
|
bind:ref
|
||||||
class={cn("bg-background flex h-10 items-center space-x-1 rounded-md border p-1", className)}
|
class={cn("bg-background flex h-10 items-center space-x-1 rounded-md border p-1", className)}
|
||||||
{...$$restProps}
|
{...restProps}
|
||||||
>
|
/>
|
||||||
<slot />
|
|
||||||
</MenubarPrimitive.Root>
|
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ Eine Kanone ist eine Vorrichtung zum Beschleunigen von Projektilen. Eine Kanone
|
|||||||
|
|
||||||
## Maße
|
## Maße
|
||||||
|
|
||||||
- Länge: 230 Block
|
- Länge: 230 Block
|
||||||
- Breite: 35 Block (+ 4 Block Design pro Seite)
|
- Breite: 35 Block (+ 4 Block Design pro Seite)
|
||||||
- Höhe: 30 Block + 20 Block Design
|
- Höhe: 30 Block + 20 Block Design
|
||||||
- Tiefe: Bis zu 8 Block unter dem Meeresspiegel
|
- Tiefe: Bis zu 8 Block unter dem Meeresspiegel
|
||||||
|
|
||||||
Bei jedem WarShip müssen sich mindestens 10% der absoluten Blöcke (45.000 Blöcke) über der Wasserlinie befinden.
|
Bei jedem WarShip müssen sich mindestens 10% der absoluten Blöcke (45.000 Blöcke) über der Wasserlinie befinden.
|
||||||
|
|
||||||
@@ -45,20 +45,22 @@ Wasser darf nicht zum Schutz des eigenen WarShips missbraucht werden.
|
|||||||
Größere Hohlräume im Rumpf zum Ausweichen feindlicher Schüsse sind nicht gestattet, auch nicht während des Kampfes. Jedes WarShip braucht eine Flagge.
|
Größere Hohlräume im Rumpf zum Ausweichen feindlicher Schüsse sind nicht gestattet, auch nicht während des Kampfes. Jedes WarShip braucht eine Flagge.
|
||||||
|
|
||||||
Ein WarShip benötigt einen fortbewegungsfähigen Rumpf mit entsprechendem Antrieb (z.B. Segel, Schiffsschrauben).
|
Ein WarShip benötigt einen fortbewegungsfähigen Rumpf mit entsprechendem Antrieb (z.B. Segel, Schiffsschrauben).
|
||||||
Der Rumpf muss mindestens einen Block tief unter Wasser sowie mindestens 5 Block über dem Meeresspiegel sein (dies gilt auch während des Kampfes relativ zur Wasseroberfläche). Der Rumpf darf max. 16 Block hoch sein.
|
Der Rumpf muss mindestens einen Block tief unter Wasser sowie mindestens 5 Block über dem Meeresspiegel sein (dies gilt auch während des Kampfes relativ zur Wasseroberfläche). Der Rumpf wird ab Wasserienie gemessen und darf max. 16 Blöcke hoch sein.
|
||||||
|
|
||||||
Jedes WarShip benötigt eine Brücke, welche die folgenden Kriterien erfüllt:
|
Jedes WarShip benötigt eine Brücke, welche die folgenden Kriterien erfüllt:
|
||||||
|
|
||||||
- Min. 50 begehbare Blöcke
|
- Min. 50 begehbare Blöcke
|
||||||
- Min. 2 Block hoch im gesamten Brückenraum
|
- Min. 2 Block hoch im gesamten Brückenraum
|
||||||
- Ansteuerung von min. zwei zum Gegner gewandten Scheinwerfer
|
- Ansteuerung von min. zwei zum Gegner gewandten Scheinwerfer
|
||||||
- Optische Brückeneinrichtung
|
- Optische Brückeneinrichtung
|
||||||
|
|
||||||
## Anti-Lag-Regeln
|
## Anti-Lag-Regeln
|
||||||
|
|
||||||
Clocks müssen sich mit Ende ihres Einsatzzweckes selbst abschalten.
|
Clocks müssen sich mit Ende ihres Einsatzzweckes selbst abschalten.
|
||||||
|
|
||||||
Sämtliche Redstonetechnik zum Schutz des eigenen WarShips muss ihre Aktivität vor dem Verteilen der Kits eingestellt haben.
|
Sämtliche Redstonetechnik zum Schutz des eigenen WarShips muss ihre Aktivität vor dem Verteilen der Kits eingestellt haben.
|
||||||
Raketen und Flugmaschinen
|
|
||||||
|
## Raketen und Flugmaschinen
|
||||||
|
|
||||||
Ein WarShip darf sich maximal 12 Block vom Technikbereich an weit ausfahren, davon ausgenommen sind Raketen und Flugmaschinen. Raketen und Flugmaschinen dürfen sich im Flug nicht in mehrere Schleim/Honigfahrzeuge aufteilen.
|
Ein WarShip darf sich maximal 12 Block vom Technikbereich an weit ausfahren, davon ausgenommen sind Raketen und Flugmaschinen. Raketen und Flugmaschinen dürfen sich im Flug nicht in mehrere Schleim/Honigfahrzeuge aufteilen.
|
||||||
|
|
||||||
@@ -74,6 +76,6 @@ Es dürften maximal 1000 der vorverbauten Slime- + Honig- + TNT-Blöcke das WarS
|
|||||||
|
|
||||||
Der Kampf endet, wenn:
|
Der Kampf endet, wenn:
|
||||||
|
|
||||||
- Der Kampf länger als 20 Minuten dauert
|
- Der Kampf länger als 20 Minuten dauert
|
||||||
- Der Anführer eines Teams tot ist
|
- Der Anführer eines Teams tot ist
|
||||||
- Ein WarShip zu 7% beschädigt wurde
|
- Ein WarShip zu 7% beschädigt wurde
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import "$lib/styles/app.css";
|
|||||||
import { astroI18n } from "astro-i18n";
|
import { astroI18n } from "astro-i18n";
|
||||||
import { SEO } from "astro-seo";
|
import { SEO } from "astro-seo";
|
||||||
import { ClientRouter } from "astro:transitions";
|
import { ClientRouter } from "astro:transitions";
|
||||||
const { title, description, clientSideRouter = true } = Astro.props.frontmatter || Astro.props;
|
const { title, description, clientSideRouter = true, autoDarkMode = true } = Astro.props.frontmatter || Astro.props;
|
||||||
import "../../public/fonts/roboto/roboto.css";
|
import "../../public/fonts/roboto/roboto.css";
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -32,11 +32,13 @@ import "../../public/fonts/roboto/roboto.css";
|
|||||||
}))}
|
}))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<script is:inline data-astro-rerun>
|
{autoDarkMode && (
|
||||||
if (localStorage["theme-mode"] === "light" || (!("theme-mode" in localStorage) && window.matchMedia("(prefers-color-scheme: light)").matches)) {
|
<script is:inline data-astro-rerun>
|
||||||
document.documentElement.classList.remove("dark");
|
if (localStorage["theme-mode"] === "light" || (!("theme-mode" in localStorage) && window.matchMedia("(prefers-color-scheme: light)").matches)) {
|
||||||
}
|
document.documentElement.classList.remove("dark");
|
||||||
</script>
|
}
|
||||||
|
</script>
|
||||||
|
)}
|
||||||
|
|
||||||
<slot name="head" />
|
<slot name="head" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
---
|
---
|
||||||
import {Image} from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import Basic from "./Basic.astro";
|
import Basic from "./Basic.astro";
|
||||||
import "../styles/button.css";
|
import "../styles/button.css";
|
||||||
import localLogo from "../images/logo.png";
|
import localLogo from "../images/logo.png";
|
||||||
import {YoutubeSolid, DiscordSolid, FileCodeSolid} from "flowbite-svelte-icons";
|
import { YoutubeSolid, DiscordSolid, FileCodeSolid } from "flowbite-svelte-icons";
|
||||||
import {t} from "astro-i18n";
|
import { t } from "astro-i18n";
|
||||||
import {l} from "../util/util";
|
import { l } from "../util/util";
|
||||||
|
|
||||||
import Navbar from "@components/Navbar.svelte";
|
import Navbar from "@components/Navbar.svelte";
|
||||||
|
|
||||||
import ServerStatus from "../components/ServerStatus.svelte";
|
import ServerStatus from "../components/ServerStatus.svelte";
|
||||||
|
|
||||||
const {title, description} = Astro.props;
|
const { title, description, transparentFooter = true } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<Basic title={title} description={description}>
|
<Basic title={title} description={description} autoDarkMode={false}>
|
||||||
<slot name="head" slot="head"/>
|
<slot name="head" slot="head" />
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div class="min-h-screen flex flex-col">
|
<div class="min-h-screen flex flex-col">
|
||||||
<Navbar client:idle>
|
<Navbar client:idle>
|
||||||
<Image src={localLogo} alt={t("navbar.logo.alt")} width="44" height="44" quality="max"
|
<Image src={localLogo} alt={t("navbar.logo.alt")} width="44" height="44" quality="max" class="mr-2 p-1 bg-black rounded-full" slot="logo" />
|
||||||
class="mr-2 p-1 bg-black rounded-full" slot="logo"/>
|
|
||||||
</Navbar>
|
</Navbar>
|
||||||
<main class="flex-1" data-pagefind-body>
|
<main class="flex-1" data-pagefind-body>
|
||||||
<slot/>
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
<footer class="bg-gray-900 w-full min-h-80 mt-4 pb-2 rounded-t-2xl flex flex-col dark:bg-neutral-900">
|
<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="flex-1 flex justify-evenly items-center md:items-start mt-4 md:flex-row flex-col gap-y-4">
|
||||||
<div class="footer-card">
|
<div class="footer-card">
|
||||||
<h1>Serverstatus</h1>
|
<h1>Serverstatus</h1>
|
||||||
@@ -45,14 +47,17 @@ const {title, description} = Astro.props;
|
|||||||
<div class="footer-card">
|
<div class="footer-card">
|
||||||
<h1>Social Media</h1>
|
<h1>Social Media</h1>
|
||||||
<a class="flex" href="/youtube">
|
<a class="flex" href="/youtube">
|
||||||
<YoutubeSolid class="mr-2"/>
|
<YoutubeSolid class="mr-2" />
|
||||||
YouTube</a>
|
YouTube</a
|
||||||
|
>
|
||||||
<a class="flex" href="/discord">
|
<a class="flex" href="/discord">
|
||||||
<DiscordSolid class="mr-2"/>
|
<DiscordSolid class="mr-2" />
|
||||||
Discord</a>
|
Discord</a
|
||||||
|
>
|
||||||
<a class="flex" href="https://git.steamwar.de">
|
<a class="flex" href="https://git.steamwar.de">
|
||||||
<FileCodeSolid class="mr-2"/>
|
<FileCodeSolid class="mr-2" />
|
||||||
Gitea</a>
|
Gitea</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm text-white text-center mt-1">© SteamWar.de - Made with ❤️ by Chaoscaot</span>
|
<span class="text-sm text-white text-center mt-1">© SteamWar.de - Made with ❤️ by Chaoscaot</span>
|
||||||
@@ -77,4 +82,4 @@ const {title, description} = Astro.props;
|
|||||||
.match {
|
.match {
|
||||||
width: min(100vw, 70em);
|
width: min(100vw, 70em);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
import NavbarLayout from "./NavbarLayout.astro";
|
import NavbarLayout from "./NavbarLayout.astro";
|
||||||
import BackgroundImage from "../components/BackgroundImage.astro";
|
import BackgroundImage from "../components/BackgroundImage.astro";
|
||||||
|
|
||||||
const {title, description} = Astro.props;
|
const { title, description } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<NavbarLayout title={title} description={description}>
|
<NavbarLayout title={title} description={description}>
|
||||||
<slot name="head" slot="head"/>
|
<slot name="head" slot="head" />
|
||||||
<div class="h-screen w-screen fixed -z-10">
|
<div class="h-screen w-screen fixed -z-10">
|
||||||
<BackgroundImage />
|
<BackgroundImage />
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto bg-gray-100 p-8 rounded-b-md shadow-md pt-14 relative
|
<div class="mx-auto p-8 rounded-b-md border-x-gray-100 shadow-md pt-14 relative
|
||||||
dark:text-white dark:bg-neutral-900" style="width: min(100%, 75em);">
|
text-white backdrop-blur-3xl" style="width: min(100%, 75em);">
|
||||||
<slot/>
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</NavbarLayout>
|
</NavbarLayout>
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ import App from "../../components/admin/App.svelte";
|
|||||||
import Basic from "../../layouts/Basic.astro";
|
import Basic from "../../layouts/Basic.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Basic clientSideRouter={false}>
|
<Basic clientSideRouter={false} autoDarkMode={false}>
|
||||||
<App client:only="svelte"/>
|
<App client:only="svelte" />
|
||||||
</Basic>
|
</Basic>
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import Basic from "../../layouts/Basic.astro";
|
import Basic from "../../layouts/Basic.astro";
|
||||||
import App from "@components/moderator/App.svelte";
|
import App from "@components/moderator/App.svelte";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Basic clientSideRouter={false}>
|
<Basic clientSideRouter={false} autoDarkMode={false}>
|
||||||
<App client:only="svelte"/>
|
<App client:only="svelte" />
|
||||||
</Basic>
|
</Basic>
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
---
|
---
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import NavbarLayout from "@layouts/NavbarLayout.astro";
|
import NavbarLayout from "@layouts/NavbarLayout.astro";
|
||||||
import {getCollection} from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
import {astroI18n} from "astro-i18n";
|
import { astroI18n } from "astro-i18n";
|
||||||
|
|
||||||
import {Image} from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import Card from "@components/Card.svelte";
|
import Card from "@components/Card.svelte";
|
||||||
import {CaretRight, Pause, Rocket, Crosshair1} from "@astropub/icons";
|
import { CaretRight, Pause, Rocket, Crosshair1 } from "@astropub/icons";
|
||||||
import {t} from "astro-i18n";
|
import { t } from "astro-i18n";
|
||||||
import {l} from "@utils/util";
|
import { l } from "@utils/util";
|
||||||
import PlayerCount from "@components/PlayerCount.svelte";
|
import PlayerCount from "@components/PlayerCount.svelte";
|
||||||
import "../../public/fonts/barlow-condensed/barlow-condensed.css";
|
import "../../public/fonts/barlow-condensed/barlow-condensed.css";
|
||||||
import {type Player} from "../components/types/data";
|
import { type Player } from "../components/types/data";
|
||||||
import PostComponent from "../components/PostComponent.astro";
|
import PostComponent from "../components/PostComponent.astro";
|
||||||
import BackgroundImage from "../components/BackgroundImage.astro";
|
import BackgroundImage from "../components/BackgroundImage.astro";
|
||||||
|
|
||||||
const teamMember: { [key: string]: Player[]} = await fetch(import.meta.env.PUBLIC_API_SERVER + "/data/team")
|
const teamMember: { [key: string]: Player[] } = await fetch(import.meta.env.PUBLIC_API_SERVER + "/data/team").then((value) => value.json());
|
||||||
.then(value => value.json());
|
|
||||||
|
|
||||||
const posts = await getCollection("announcements", entry => entry.id.split("/")[0] === astroI18n.locale);
|
const posts = await getCollection("announcements", (entry) => entry.id.split("/")[0] === astroI18n.locale);
|
||||||
|
|
||||||
const germanPosts = await getCollection("announcements", entry => entry.id.split("/")[0] === astroI18n.fallbackLocale);
|
const germanPosts = await getCollection("announcements", (entry) => entry.id.split("/")[0] === astroI18n.fallbackLocale);
|
||||||
|
|
||||||
germanPosts.forEach(value => {
|
germanPosts.forEach((value) => {
|
||||||
if (posts.find(post => post.data.key === value.data.key)) {
|
if (posts.find((post) => post.data.key === value.data.key)) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
posts.push(value);
|
posts.push(value);
|
||||||
@@ -43,27 +42,29 @@ const prefixColorMap: {
|
|||||||
};
|
};
|
||||||
---
|
---
|
||||||
|
|
||||||
<NavbarLayout title={t("home.page")} description="SteamWar.de Homepage">
|
<NavbarLayout title={t("home.page")} description="SteamWar.de Homepage" transparentFooter={false}>
|
||||||
<div class="w-full h-screen relative mb-4">
|
<div class="w-full h-screen relative mb-4 z-10">
|
||||||
<div style="height: calc(100vh + 1rem)">
|
<div style="height: calc(100vh + 1rem)">
|
||||||
<BackgroundImage />
|
<BackgroundImage />
|
||||||
</div>
|
</div>
|
||||||
<drop-in class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 flex flex-col items-center">
|
<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"
|
<h1
|
||||||
style="transition: transform .7s ease-out, opacity .7s linear; filter: drop-shadow(2px 2px 5px black);">
|
class="text-4xl sm:text-6xl md:text-8xl font-extrabold text-white -translate-y-16 opacity-0 barlow tracking-wider"
|
||||||
<span class="bg-gradient-to-tr from-yellow-400 to-yellow-300 bg-clip-text text-transparent">{t("home.title.first")}</span><span
|
style="transition: transform .7s ease-out, opacity .7s linear; filter: drop-shadow(2px 2px 5px black);"
|
||||||
class="text-neutral-600">{t("home.title.second")}</span>
|
>
|
||||||
|
<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>
|
||||||
</h1>
|
</h1>
|
||||||
<text-carousel class="h-20 w-full relative select-none">
|
<text-carousel class="h-20 w-full relative select-none">
|
||||||
<h2 class="-translate-y-16">{t("home.subtitle.1")}</h2>
|
<h2 class="-translate-y-16">{t("home.subtitle.1")}</h2>
|
||||||
<h2>{t("home.subtitle.2")}
|
<h2>
|
||||||
|
{t("home.subtitle.2")}
|
||||||
<PlayerCount client:idle />
|
<PlayerCount client:idle />
|
||||||
</h2>
|
</h2>
|
||||||
<h2>{t("home.subtitle.3")}</h2>
|
<h2>{t("home.subtitle.3")}</h2>
|
||||||
</text-carousel>
|
</text-carousel>
|
||||||
<a href={l("join")} class="btn btn-ghost mt-32 px-8 flex"
|
<a href={l("join")} class="btn btn-ghost mt-32 px-8 flex" style="animation: normal flyIn forwards 1.2s ease-out"
|
||||||
style="animation: normal flyIn forwards 1.2s ease-out">{t("home.join")}
|
>{t("home.join")}
|
||||||
<CaretRight width="24" height="24"/>
|
<CaretRight width="24" height="24" />
|
||||||
</a>
|
</a>
|
||||||
<style>
|
<style>
|
||||||
@keyframes flyIn {
|
@keyframes flyIn {
|
||||||
@@ -141,18 +142,18 @@ const prefixColorMap: {
|
|||||||
<section class="w-full flex flex-col items-center justify-center shadow-2xl rounded-b-2xl pb-8">
|
<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">
|
<div class="py-10 flex flex-col lg:flex-row">
|
||||||
<Card client:idle>
|
<Card client:idle>
|
||||||
<Crosshair1 height="64" width="64"/>
|
<Crosshair1 height="64" width="64" />
|
||||||
<h1>{t("home.benefits.fights.title")}</h1>
|
<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.1")}</p>
|
||||||
<p class="mt-4">{t("home.benefits.fights.description.2")}</p>
|
<p class="mt-4">{t("home.benefits.fights.description.2")}</p>
|
||||||
</Card>
|
</Card>
|
||||||
<Card client:idle>
|
<Card client:idle>
|
||||||
<Rocket height="64" width="64"/>
|
<Rocket height="64" width="64" />
|
||||||
<h1>{t("home.benefits.bau.title")}</h1>
|
<h1>{t("home.benefits.bau.title")}</h1>
|
||||||
<p class="mt-4">{t("home.benefits.bau.description")}</p>
|
<p class="mt-4">{t("home.benefits.bau.description")}</p>
|
||||||
</Card>
|
</Card>
|
||||||
<Card client:idle>
|
<Card client:idle>
|
||||||
<Pause height="64" width="64"/>
|
<Pause height="64" width="64" />
|
||||||
<h1>{t("home.benefits.minigames.title")}</h1>
|
<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.1")}</p>
|
||||||
<p class="mt-4">{t("home.benefits.minigames.description.2")}</p>
|
<p class="mt-4">{t("home.benefits.minigames.description.2")}</p>
|
||||||
@@ -160,23 +161,29 @@ const prefixColorMap: {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="w-full py-12 flex flex-wrap justify-center">
|
<section class="w-full py-12 flex flex-wrap justify-center">
|
||||||
{Object.entries(teamMember).map(([prefix, players]) => (
|
{
|
||||||
<Fragment>
|
Object.entries(teamMember).map(([prefix, players]) => (
|
||||||
{players.map((v, index) => (
|
<Fragment>
|
||||||
<div class="inline-flex flex-col justify-end">
|
{players.map((v, index) => (
|
||||||
{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}
|
<div class="inline-flex flex-col justify-end">
|
||||||
<Card extraClasses={`pt-8 pb-10 px-8 w-fit shadow-md ${prefixColorMap[prefix]}`} client:idle>
|
{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}
|
||||||
<figure class="flex flex-col items-center" style="width: 150px">
|
<Card extraClasses={`pt-8 pb-10 px-8 w-fit shadow-md ${prefixColorMap[prefix]}`} client:idle>
|
||||||
<figcaption class="text-center mb-4 text-2xl">{v.name}</figcaption>
|
<figure class="flex flex-col items-center" style="width: 150px">
|
||||||
<Image src={`${import.meta.env.PUBLIC_API_SERVER}/data/skin/${v.uuid}`}
|
<figcaption class="text-center mb-4 text-2xl">{v.name}</figcaption>
|
||||||
class="transition duration-300 ease-in-out hover:scale-110 hover:backdrop-blur-lg hover:drop-shadow-2xl"
|
<Image
|
||||||
alt={v.name + "s bust"} width="150" height="150"/>
|
src={`${import.meta.env.PUBLIC_API_SERVER}/data/skin/${v.uuid}`}
|
||||||
</figure>
|
class="transition duration-300 ease-in-out hover:scale-110 hover:backdrop-blur-lg hover:drop-shadow-2xl"
|
||||||
</Card>
|
alt={v.name + "s bust"}
|
||||||
</div>
|
width="150"
|
||||||
))}
|
height="150"
|
||||||
</Fragment>
|
/>
|
||||||
))}
|
</figure>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Fragment>
|
||||||
|
))
|
||||||
|
}
|
||||||
</section>
|
</section>
|
||||||
</NavbarLayout>
|
</NavbarLayout>
|
||||||
|
|
||||||
@@ -184,13 +191,17 @@ const prefixColorMap: {
|
|||||||
text-carousel {
|
text-carousel {
|
||||||
> * {
|
> * {
|
||||||
@apply absolute top-0 left-0 w-full text-xl sm:text-4xl italic text-white text-center opacity-0;
|
@apply absolute top-0 left-0 w-full text-xl sm:text-4xl italic text-white text-center opacity-0;
|
||||||
transition: transform .5s ease-out, opacity .5s linear;
|
transition:
|
||||||
|
transform 0.5s ease-out,
|
||||||
|
opacity 0.5s linear;
|
||||||
text-shadow: 2px 2px 5px black;
|
text-shadow: 2px 2px 5px black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.barlow {
|
.barlow {
|
||||||
font-family: Barlow Condensed, sans-serif;
|
font-family:
|
||||||
|
Barlow Condensed,
|
||||||
|
sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
@@ -207,7 +218,7 @@ const prefixColorMap: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
> svg {
|
> svg {
|
||||||
@apply transition-transform duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl
|
@apply transition-transform duration-300 ease-in-out hover:scale-110 hover:drop-shadow-2xl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ table {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
tr:nth-child(odd) {
|
tr:nth-child(odd) {
|
||||||
@apply bg-neutral-200 dark:bg-neutral-800;
|
@apply backdrop-brightness-125;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user