add features page

This commit is contained in:
2025-11-23 03:48:04 +01:00
parent 9ca8cc3bef
commit be8b19463c
8 changed files with 172 additions and 2 deletions

View File

@@ -3,7 +3,7 @@
import MenuSignup from '@assets/img/menu-signup.webp'; import MenuSignup from '@assets/img/menu-signup.webp';
import MenuRules from '@assets/img/menu-rules.webp'; import MenuRules from '@assets/img/menu-rules.webp';
import MenuFaq from '@assets/img/menu-faq.webp'; import MenuFaq from '@assets/img/menu-faq.webp';
import MenuFeedback from '@assets/img/menu-feedback.webp'; import MenuFeature from '@assets/img/menu-features.webp';
import MenuAdmins from '@assets/img/menu-admins.webp'; import MenuAdmins from '@assets/img/menu-admins.webp';
import MenuButton from '@assets/img/menu-button.webp'; import MenuButton from '@assets/img/menu-button.webp';
import MenuInventoryBar from '@assets/img/menu-inventory-bar.webp'; import MenuInventoryBar from '@assets/img/menu-inventory-bar.webp';
@@ -41,6 +41,12 @@
href: 'faq', href: 'faq',
active: false active: false
}, },
{
name: 'Features',
sprite: MenuFeature.src,
href: 'features',
active: false
},
{ {
name: 'Admins', name: 'Admins',
sprite: MenuAdmins.src, sprite: MenuAdmins.src,

View File

@@ -0,0 +1,62 @@
<script lang="ts">
import cat1 from '@assets/img/cat1.jpg';
import cat2 from '@assets/img/cat2.jpg';
import { onMount } from 'svelte';
// html bindings
let imageContainer: HTMLDivElement;
// types
interface Props {
images?: { path: string; text?: string }[];
}
// states
const { images = [{ path: cat1.src }, { path: cat2.src }] }: Props = $props();
let currentImage = $state<HTMLDivElement | null>(null);
// lifecycle
onMount(() => {
currentImage = imageContainer.children.item(0) as HTMLDivElement | null;
});
// callback
function scrollPrev() {
if (!currentImage!.previousElementSibling) return;
currentImage!.previousElementSibling.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
currentImage = currentImage!.previousElementSibling as HTMLDivElement;
}
function scrollNext() {
if (!currentImage!.nextElementSibling) return;
currentImage!.nextElementSibling.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
currentImage = currentImage!.nextElementSibling as HTMLDivElement;
}
</script>
<div class="relative">
<div class="carousel w-full aspect-video rounded items-center" bind:this={imageContainer}>
{#each images as image (image.path)}
<div class="carousel-item w-full">
<img src={image.path} class="w-full object-cover" alt={image.text ?? image.path} />
</div>
{/each}
</div>
{#if currentImage}
<div class="absolute top-0 left-2 h-full flex items-center">
<button
class="backdrop-invert-75 w-10 h-10 rounded-full flex justify-center items-center"
aria-label="previous"
onclick={scrollPrev}><span class="iconify iconify-[heroicons--chevron-left] w-2/5 h-2/5"></span></button
>
</div>
<div class="absolute top-0 right-2 h-full flex items-center">
<button
class="backdrop-invert-75 w-10 h-10 rounded-full flex justify-center items-center"
aria-label="next"
onclick={scrollNext}><span class="iconify iconify-[heroicons--chevron-right] w-2/5 h-2/5"></span></button
>
</div>
{/if}
</div>

BIN
src/assets/img/cat1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
src/assets/img/cat2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 B

102
src/pages/features.astro Normal file
View File

@@ -0,0 +1,102 @@
---
import WebsiteLayout from '@layouts/website/WebsiteLayout.astro';
import ImageCarousel from '@app/website/features/ImageCarousel.svelte';
const features = [
{
name: 'Pixelblock',
details: [
`<p>Erstelle deinen eigenen Block im Miniformat. Du kannst einen leeren Block craften, den du anschließend frei
nach deinen Vorstellungen mit Inhalt füllen kannst! Ob die letzten Details zu deinem Bauwerk oder (sehr teure) vertikale
Stufen pure Freiheit!</p>`,
`<p>Leider sind Pixelblöcke für Bedrock-Spieler nicht nutzbar und auch nicht sichtbar!</p>`
]
},
{
name: 'Trank des Schnüfflers',
details: [
`<p> Füttere einen Schnüffler mit Zucker. Er wird verrückt und rennt umher und explodiert! Dabei droppt er aber
einen Trank, den Trank des Schnüfflers. Trink ihn, und du kannst für eine kurze Zeit alle Erze in deiner Umgebung
erschnüffeln!</p>`
]
},
{
name: 'Voicemod',
details: [
`<p>Auf unserem Server ist Simple-Voice-Chat verfügbar. Damit kannst du dich mit anderen Spielern im Spiel
unterhalten. Das Nutzen ist natürlich optional. Für Bedrock-Spieler ist Simple-Voice-Chat leider nicht verfügbar.</p>`,
`<p>Tutorial für die Einrichtung:
<a class="link" href="https://www.youtube.com/watch?v=GQdEnX2Dkh4" target="_blank">https://www.youtube.com/watch?v=GQdEnX2Dkh4</a></p>`
]
},
{
name: 'Blutmond',
details: [
`<p> Abends, meist gegen 18 Uhr, finden gelegentlich Events statt, bei denen du Items gewinnen kannst und in
kleinen Minispielen gegen deine Mitspieler antrittst. Die genauen Abläufe siehst du, wenn du abends auf dem Server
bist.</p>`
]
},
{
name: 'Erweiterte Spieleinstellungen',
details: [
`<p>Mit <code>/settings</code> erreichst du einige Quality-of-Life-Features welche dein Spielerlebnis verbessern.
Zum Beispiel das automatische Öffnen von Doppeltüren bis hin zum Ausblenden der Beitrittsnachrichten im Chat anderer
Spieler.</p>`
]
},
{
name: 'Miniblöcke des Wandernden Händlers',
details: [
`<p>Der wandernde Händler verkauft neben seinen normalen Items auch miniversionen von Blöcken, die sich als
Dekoration hervorragend eignen!</p>`
]
},
{
name: 'Platzierbare Blöcke in Minecarts',
details: [
`<p>Du kannst jeden Vollen Block in ein leeres Minecart platzieren. Das ist zwar deutlich ineffizienter als ein
Kistenminecart, hat aber deutlich mehr Stil!</p>`
]
},
{
name: 'Recoverycompass bleiben nach Toden im Inventar',
details: [
`<p>Finde schneller zu deinem Todespunkt nach deinem Tod zurück der Recoverykompass bleib im Inventar. Es ist
deine Entscheidung, ob du den Inventarplatz dafür opferst oder nicht. Zum Start erhältst du einen for Free!</p>`
]
},
{
name: 'PVP-Modus',
details: [
`<p> Du suchst den Nervenkitzel? Im PVP-Modus (ehemals Vogelfrei) dürfen dich alle anderen Spieler, welche
ebenfalls im PVP-Modus sind angreifen und töten. Deine Items müssen nicht zurückerstattet werden. Bauwerke und Kisten
sind aber weiterhin geschützt. Aktivieren kannst du den Modus mit <code>/pvp</code>.</p>`
]
}
];
---
<WebsiteLayout title="Features">
<div class="mx-4 my-6 sm:mx-12 sm:my-12 xl:mx-32 2xl:mx-64">
<h1 class="text-3xl lg:text-5xl mb-16 text-center">Features</h1>
<div class="grid md:grid-cols-2 gap-y-8 md:gap-x-6 lg:gap-x-18 xl:gap-x-26 2xl:gap-x-36">
{
features.map((feature) => (
<>
<div>
<h3 class="text-xl mb-4 underline">{feature.name}</h3>
<ol class="list-disc space-y-2 ml-3">
{feature.details.map((detail) => (
<li class="text-base/7" set:html={detail} />
))}
</ol>
</div>
<div>
<ImageCarousel client:idle />
</div>
</>
))
}
</div>
</div>
</WebsiteLayout>

View File

@@ -59,7 +59,7 @@ export async function sendWebhook<T extends WebhookAction>(action: T, data: Webh
retry: retries + 1, retry: retries + 1,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
error: e.message, error: e.message
}, },
'error while sending webhook' 'error while sending webhook'
); );