aboutsummaryrefslogtreecommitdiff
path: root/apps/website/src/components/base
diff options
context:
space:
mode:
Diffstat (limited to 'apps/website/src/components/base')
-rw-r--r--apps/website/src/components/base/Button.astro64
-rw-r--r--apps/website/src/components/base/Card.astro22
-rw-r--r--apps/website/src/components/base/CodeBlock.astro21
-rw-r--r--apps/website/src/components/base/Footer.astro42
-rw-r--r--apps/website/src/components/base/FormattedDate.astro17
-rw-r--r--apps/website/src/components/base/Header.astro62
-rw-r--r--apps/website/src/components/base/Link.astro17
-rw-r--r--apps/website/src/components/base/Navbar.astro21
-rw-r--r--apps/website/src/components/base/NavbarElement.astro89
-rw-r--r--apps/website/src/components/base/Paragraph.astro28
-rw-r--r--apps/website/src/components/base/ScreenOverlay.astro16
-rw-r--r--apps/website/src/components/base/ScrollbarOverlayContainer.astro16
-rw-r--r--apps/website/src/components/base/Section.astro51
-rw-r--r--apps/website/src/components/base/Slider.astro73
-rw-r--r--apps/website/src/components/base/Tag.astro13
-rw-r--r--apps/website/src/components/base/navbar/Navbar.astro23
-rw-r--r--apps/website/src/components/base/navbar/NavbarElement.astro100
17 files changed, 430 insertions, 245 deletions
diff --git a/apps/website/src/components/base/Button.astro b/apps/website/src/components/base/Button.astro
index adbc656..e529dc5 100644
--- a/apps/website/src/components/base/Button.astro
+++ b/apps/website/src/components/base/Button.astro
@@ -1,26 +1,28 @@
---
-import type { Icons } from "@components/icons/Icon.astro";
-import Icon from "@components/icons/Icon.astro";
-import type { HTMLAttributes } from "astro/types";
+import type { Icons } from '@components/icons/Icon.astro';
+import Icon from '@components/icons/Icon.astro';
+import type { HTMLAttributes } from 'astro/types';
const styles = {
- primary: "bg-blue-500 text-white hover:bg-blue-400 active:bg-blue-600 disabled:bg-blue-800 disabled:text-white-1/4",
- secondary: "bg-blue-100 text-blue-500 hover:bg-blue-200 active:bg-blue-300 disabled:bg-blue-50 disabled:text-blue-200",
-}
+ // TODO: adjust active / disabled colors
+ primary: 'bg-blue-500 text-white hover:bg-blue-400 active:bg-blue-600 disabled:bg-blue-800 disabled:text-white-1/4',
+ secondary: 'bg-blue-20 text-blue-60 border-[1px] border-blue-30 hover:bg-blue-200 active:bg-blue-300 disabled:bg-blue-50 disabled:text-blue-200',
+ ghost: 'bg-transparent text-blue-500 hover:bg-blue-20 active:bg-blue-30 disabled:bg-transparent disabled:text-blue-200',
+};
const sizes = {
- sm: "px-4 py-2 text-sm",
- md: "px-5 py-3 text-md",
- lg: "px-6 py-3 text-lg rounded-2xl"
-}
+ sm: 'px-4 py-2 text-sm',
+ md: 'px-5 py-3 text-md',
+ lg: 'px-6 py-3 text-lg rounded-2xl',
+};
const iconSize = {
- sm: 15,
- md: 18,
- lg: 24
-}
+ sm: 17,
+ md: 20,
+ lg: 24,
+};
-interface Props extends HTMLAttributes<"button"> {
+interface Props extends HTMLAttributes<'button'> {
style?: keyof typeof styles
size?: keyof typeof sizes
text?: string
@@ -30,28 +32,28 @@ interface Props extends HTMLAttributes<"button"> {
}
const {
- style = "primary",
- size = "md",
- text = "",
- iconLeft = "",
- iconRight = "",
+ style = 'primary',
+ size = 'md',
+ text = '',
+ iconLeft = '',
+ iconRight = '',
...rest
} = Astro.props;
const className = [
- "flex flex-row justify-center items-center text-center focus-visible:ring-offset-4 focus-visible:outline-offset-4",
- "rounded-xl font-medium",
+ 'flex flex-row justify-center items-center text-center focus-visible:ring-offset-4 focus-visible:outline-offset-4',
+ 'rounded-xl font-medium',
styles[style],
sizes[size],
- "transition-colors",
- rest.class
-].join(" ");
+ 'transition-colors',
+ rest.class,
+].join(' ');
-const Element = rest.href ? "a" : "button" as any;
+const Element = rest.href ? 'a' : 'button' as any;
---
-<Element {...rest} class={className}>
- {iconLeft && <span class="mr-2"><Icon icon={iconLeft} size={iconSize[size]}></Icon></span>}
- {text ? text : <slot />}
- {iconRight && <span class="ml-2"><Icon icon={iconRight} size={iconSize[size]}></Icon></span>}
-</Element>
+ <Element {...rest} class={className}>
+ {iconLeft && <span class="mr-2"><Icon icon={iconLeft} size={iconSize[size]}></Icon></span>}
+ {text || <slot/>}
+ {iconRight && <span class="ml-2"><Icon icon={iconRight} size={iconSize[size]}></Icon></span>}
+ </Element>
diff --git a/apps/website/src/components/base/Card.astro b/apps/website/src/components/base/Card.astro
new file mode 100644
index 0000000..6438273
--- /dev/null
+++ b/apps/website/src/components/base/Card.astro
@@ -0,0 +1,22 @@
+---
+import type { Icons } from '@components/icons/Icon.astro';
+import Icon from '@components/icons/Icon.astro';
+import type { HTMLAttributes } from 'astro/types';
+
+interface Props extends HTMLAttributes<'div'> {
+ icon: Icons
+ text?: string
+}
+
+const {
+ icon,
+ text = 'Hiiii',
+ ...rest
+} = Astro.props;
+---
+
+<!-- pt-1 added temporarily cause for some reason the icon's padding doesn't apply unless I add this. the wonders of CSS. -->
+<div {...rest} class="rounded-xl bg-primary-100 w-[256px] shrink-0">
+ <Icon icon={icon} size={48} class="my-[28px] mx-auto text-white"></Icon>
+ <p class="text-white mx-auto bg-primary-200 rounded-b-xl text-[14px] py-[7px] pl-[12px] pr-[32px]">{text}</p>
+</div>
diff --git a/apps/website/src/components/base/CodeBlock.astro b/apps/website/src/components/base/CodeBlock.astro
deleted file mode 100644
index 5991428..0000000
--- a/apps/website/src/components/base/CodeBlock.astro
+++ /dev/null
@@ -1,21 +0,0 @@
----
-
----
-
-<pre class="flex flex-col">
- <code class="whitespace-pre bg-white-light border border-gray-50 rounded-2xl text-sm">{`public class MyConfig {
-
- @Switch(name = "Sub Switch", type = OptionType.SWITCH)
- public static boolean subSwitch = false;
-
- public MyConfig() {
- super(new Mod("My Mod", ModType.UTIL_QOL), "config.json");
-
- addDependency("subSwitch", () -> {
- // TODO: Make codeblocks better lmao
- });
- }
-
-}`}</code>
-</pre>
-
diff --git a/apps/website/src/components/base/Footer.astro b/apps/website/src/components/base/Footer.astro
index b24db5f..7a9071a 100644
--- a/apps/website/src/components/base/Footer.astro
+++ b/apps/website/src/components/base/Footer.astro
@@ -1,7 +1,47 @@
---
+import Icon from '@components/icons/Icon.astro';
+import Logo from '@components/logos/Logo.astro';
+import configConst from '@config';
+import type { HTMLAttributes } from 'astro/types';
+import Link from './Link.astro';
+interface Props extends HTMLAttributes<'footer'> {}
+
+const props = Astro.props;
---
-<footer class="flex min-h-[400px] bg-blue-100 mt-4">
+<footer {...props} class="section flex justify-center items-center bg-blue-100 -mt-40 pt-20 pb-8 px-20">
+ <div class="max-w-[1024px] w-full flex flex-col gap-y-24">
+ <div class="flex flex-col gap-y-20 justify-center items-start md:flex-row md:items-start md:justify-between">
+ <div class="flex-1 flex flex-col gap-y-3 text-blue-gray">
+ <Logo logo="polyfrost.full" />
+ <p>English, USA</p> {/* hardcoded for now, todo i18n */}
+ <div class="flex flex-row gap-3">
+ <a href={configConst.socials.discord} target="_blank" class="hover:text-[#5865F2]"><Icon icon="discord" /></a>
+ <a href={configConst.socials.youtube} target="_blank" class="hover:text-[#ff0000]"><Icon icon="youtube" /></a>
+ <a href={configConst.socials.github} target="_blank" class="hover:text-[#000000]"><Icon icon="github" /></a>
+ </div>
+ </div>
+
+ <div class="flex-1 flex flex-col md:flex-row justify-end gap-8">
+ {configConst.footer.map(column => (
+ <div class="flex flex-col gap-y-3">
+ <h3 class="text-gray-700 text-md">{column.header}</h3>
+ <ul class="flex flex-col gap-y-1">
+ {column.links.map(link => (
+ <li>
+ <Link href={link.url} class="text-blue-gray text-sm text-nowrap">{link.text}</Link>
+ </li>
+ ))}
+ </ul>
+ </div>
+ ))}
+ </div>
+ </div>
+ <div class="flex flex-col items-center md:flex-row md:items-start md:justify-between">
+ <p class="text-blue-gray text-sm">© {new Date().getFullYear()} Polyfrost. All rights reserved.</p>
+ <p class="text-blue-gray text-sm">Not an official Minecraft product. Not approved by or affiliated with Mojang Studios.</p>
+ </div>
+ </div>
</footer>
diff --git a/apps/website/src/components/base/FormattedDate.astro b/apps/website/src/components/base/FormattedDate.astro
new file mode 100644
index 0000000..af538b9
--- /dev/null
+++ b/apps/website/src/components/base/FormattedDate.astro
@@ -0,0 +1,17 @@
+---
+interface Props {
+ date: Date
+}
+
+const { date } = Astro.props;
+---
+
+ <time datetime={date.toISOString()}>
+ {
+ date.toLocaleDateString('en-us', {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ })
+ }
+ </time>
diff --git a/apps/website/src/components/base/Header.astro b/apps/website/src/components/base/Header.astro
index d35ad9f..962b2d4 100644
--- a/apps/website/src/components/base/Header.astro
+++ b/apps/website/src/components/base/Header.astro
@@ -1,41 +1,54 @@
---
-import type { HTMLAttributes } from "astro/types"
+import type { HTMLAttributes } from 'astro/types';
const sizes = {
- "xxl": "h1",
- "xl": "h2",
- "lg": "h2",
- "md": "h3",
- "sm": "h4",
- "xs": "h5",
- "xxs": "h6"
+ xxl: 'h1',
+ xl: 'h2',
+ lg: 'h2',
+ md: 'h3',
+ sm: 'h4',
+ xs: 'h5',
+ xxs: 'h6',
};
-type Headers = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
+type Headers = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
interface Props extends HTMLAttributes<Headers> {
- size?: keyof typeof sizes;
- align?: "left" | "center" | "right" | "inherit";
+ size?: keyof typeof sizes
+ align?: 'left' | 'center' | 'right' | 'inherit'
+ inheritSize?: boolean
}
const {
- size = "lg",
- align = "inherit",
+ size = 'lg',
+ align = 'inherit',
+ inheritSize = false,
...attr
} = Astro.props;
const Element = sizes[size] as any; // Unfortunately gotta do this
-const className = (align == "inherit" ? "" : `text-${align} `)
- + (size == "xxl" ? " page-header" : "")
- + (attr.class ? ` ${attr.class}` : "");
+let className: string | string[] = [];
+if (!inheritSize)
+ className.push('header');
+
+if (align !== 'inherit')
+ className.push(`text-${align}`);
+
+if (size === 'xxl' || size === 'xl')
+ className.push('page-header');
+
+if (attr.class)
+ className.push(attr.class);
+
+className = className.join(' ');
---
<Element {...attr} class={className}>
- <slot />
+ <slot/>
</Element>
<style>
- h1 {
+ h1.header {
font-size: theme("fontSize.header-lg");
&.page-header {
font-size: theme("fontSize.header-page");
@@ -43,27 +56,30 @@ const className = (align == "inherit" ? "" : `text-${align} `)
font-weight: 600;
}
- h2 {
+ h2.header {
font-size: theme("fontSize.header");
+ &.page-header {
+ font-size: theme("fontSize.header-page");
+ }
font-weight: 600;
}
- h3 {
+ h3.header {
font-size: theme("fontSize.header-sm");
font-weight: 600;
}
- h4 {
+ h4.header {
font-size: theme("fontSize.body-lg");
font-weight: 500;
}
- h5 {
+ h5.header {
font-size: theme("fontSize.body");
font-weight: 500;
}
- h6 {
+ h6.header {
font-size: theme("fontSize.body-sm");
font-weight: 500;
}
diff --git a/apps/website/src/components/base/Link.astro b/apps/website/src/components/base/Link.astro
new file mode 100644
index 0000000..dfb6425
--- /dev/null
+++ b/apps/website/src/components/base/Link.astro
@@ -0,0 +1,17 @@
+---
+import type { HTMLAttributes } from 'astro/types';
+
+interface Props extends HTMLAttributes<'a'> {
+
+}
+
+const props = Astro.props;
+const className = [
+ 'text-current hover:text-blue-500 underline decoration-[transparent] hover:decoration-blue-500 transition-colors',
+ props.class,
+].join(' ');
+---
+
+<a class={className} {...props}>
+ <slot />
+</a>
diff --git a/apps/website/src/components/base/Navbar.astro b/apps/website/src/components/base/Navbar.astro
deleted file mode 100644
index a3a82fe..0000000
--- a/apps/website/src/components/base/Navbar.astro
+++ /dev/null
@@ -1,21 +0,0 @@
----
-import config from "config";
-import type { Config } from "@webtypes/Config";
-import NavbarElement from "./NavbarElement.astro";
-
----
-
-<div class="absolute w-full flex flex-row justify-center h-screen max-h-[110px] px-3">
- <nav class="w-full max-w-[1080px] flex flex-col md:flex-row justify-between items-center">
- <ul class="flex flex-row justify-start gap-4">
- {(config as Config).navbar.left.map((element, index) => (
- <NavbarElement {element} {index} />
- ))}
- </ul>
- <ul class="flex flex-row justify-end gap-4">
- {(config as Config).navbar.right.map((element, index) => (
- <NavbarElement {element} {index} />
- ))}
- </ul>
- </nav>
-</div>
diff --git a/apps/website/src/components/base/NavbarElement.astro b/apps/website/src/components/base/NavbarElement.astro
deleted file mode 100644
index b0f1282..0000000
--- a/apps/website/src/components/base/NavbarElement.astro
+++ /dev/null
@@ -1,89 +0,0 @@
----
-import ChevronDown from "@components/icons/ChevronDown.svg";
-import type { LogoType, NavbarElement } from "@webtypes/Config";
-import ScreenOverlay from "./ScreenOverlay.astro";
-import Header from "./Header.astro";
-import Tag from "./Tag.astro";
-import Logo from "@components/logos/Logo.astro";
-import ScrollbarOverlayContainer from "./ScrollbarOverlayContainer.astro";
-import Icon from "@components/icons/Icon.astro";
-
-interface Props {
- element: NavbarElement;
- index: number;
-}
-
-const {
- element,
- index
-} = Astro.props;
----
-
-<li class="sm:relative max-sm:overflow-hidden flex flex-row justify-center items-center text-center">
- <label for={`navbar-input-${index}`} class="group">
-
- {element.path ? (
- <a href={element.path} class="p-2 flex flex-row justify-center items-center text-gray-700 hover:text-blue-500">
- {element.text && element.text}
- {element.logo && <Logo size={element.logo[1] < 0 ? undefined : element.logo[1]} logo={element.logo[0] as LogoType} />}
- {element.dropdown && <Icon icon="chevron-down" />}
- </a>
- ) : (
- <p class="p-2 flex flex-row justify-center items-center text-gray-700 hover:text-blue-500 cursor-default">
- {element.text && element.text}
- {element.logo && <Logo size={element.logo[1] < 0 ? undefined : element.logo[1]} logo={element.logo[0] as LogoType} />}
- {element.dropdown && <Icon icon="chevron-down" />}
- </p>
- )}
-
- {element.dropdown && (
- <ScreenOverlay class="max-sm:group-focus-within:opacity-100" />
- <input tabindex="-1" type="checkbox" id={`navbar-input-${index}`} class="peer appearance-none absolute">
- <div class={`
- transition-opacity
- fixed md:absolute right-0 max-sm:bottom-0
- max-sm:overflow-hidden
- max-sm:max-h-[70vh] max-sm:h-screen max-sm:w-screen
- pointer-events-none opacity-0
-
- md:top-full md:right-0
-
- group-focus-within:pointer-events-auto group-focus-within:opacity-100
- focus-within:pointer-events-auto focus-within:opacity-100
- hover:pointer-events-auto hover:opacity-100
- `}>
- <ScrollbarOverlayContainer tabindex="-1" class={`
- bg-gray-50
- rounded-t-lg md:rounded-lg
- transition-transform
- max-sm:translate-y-1/3 max-sm:left-0
- group-focus-within:translate-y-0
- max-h-full md:max-h-96 overflow-y-auto
- md:shadow-lg
- `}>
- <ul class="p-4">
- {element.dropdown.map((item) => (
- <li>
- <a href={item.path} class="flex sm:min-w-[400px] sm:max-w-[400px]">
- <div class="transition-colors text-left w-full flex flex-row justify-start rounded-md items-center px-6 py-4 gap-6 hover:bg-blue-50">
- <div class="w-[36px]">
- {item.logo && <Logo size={40} logo={item.logo} />}
- </div>
-
- <div class="flex flex-col justify-start items-start">
- <div class="flex flex-row gap-2">
- <Header size="sm" class="text-gray-800">{item.name}</Header>
- {item.tag && <Tag>{item.tag}</Tag>}
- </div>
- <p class="text-sm text-gray-400 font-light">{item.description}</p>
- </div>
- </div>
- </a>
- </li>
- ))}
- </ul>
- </ScrollbarOverlayContainer>
- </div>
- )}
- </label>
-</li>
diff --git a/apps/website/src/components/base/Paragraph.astro b/apps/website/src/components/base/Paragraph.astro
index 08fbbdd..db0bff6 100644
--- a/apps/website/src/components/base/Paragraph.astro
+++ b/apps/website/src/components/base/Paragraph.astro
@@ -1,31 +1,31 @@
---
-import type { HTMLAttributes } from "astro/types";
+import type { HTMLAttributes } from 'astro/types';
const sizes = {
- xs: "text-xs",
- sm: "text-sm",
- md: "text-md",
- lg: "text-lg",
- xl: "text-xl"
-}
+ xs: 'text-xs',
+ sm: 'text-sm',
+ md: 'text-inherit',
+ lg: 'text-lg',
+ xl: 'text-xl',
+};
-interface Props extends HTMLAttributes<"p"> {
- text?: string,
+interface Props extends HTMLAttributes<'p'> {
+ text?: string
size?: keyof typeof sizes
}
const {
- text = "",
- size = "md",
+ text = '',
+ size = 'md',
...props
} = Astro.props;
const className = [
sizes[size],
- props.class
-].join(" ");
+ props.class,
+].join(' ');
---
<p class={className} {...props}>
- {text ? text : <slot />}
+ {text || <slot/>}
</p>
diff --git a/apps/website/src/components/base/ScreenOverlay.astro b/apps/website/src/components/base/ScreenOverlay.astro
index 7be8bc5..1b97152 100644
--- a/apps/website/src/components/base/ScreenOverlay.astro
+++ b/apps/website/src/components/base/ScreenOverlay.astro
@@ -1,16 +1,16 @@
---
-import type { HTMLAttributes } from "astro/types";
+import type { HTMLAttributes } from 'astro/types';
-interface Props extends HTMLAttributes<"div"> {
- zIndex?: number;
+interface Props extends HTMLAttributes<'div'> {
+ zIndex?: number
}
const {
- zIndex = 0,
- ...rest
+ zIndex = 0,
+ ...rest
} = Astro.props;
---
-<div class="pointer-events-none absolute left-0 top-0">
- <div class={`transition-opacity fixed opacity-0 w-screen h-screen z-[${zIndex}] bg-black/30 ${rest.class}`} {...rest}></div>
-</div> \ No newline at end of file
+ <div class="pointer-events-none absolute left-0 top-0">
+ <div class={`transition-opacity fixed opacity-0 w-screen h-screen z-[${zIndex}] bg-black/30 ${rest.class}`} {...rest}></div>
+ </div>
diff --git a/apps/website/src/components/base/ScrollbarOverlayContainer.astro b/apps/website/src/components/base/ScrollbarOverlayContainer.astro
index d8d315d..235dbc7 100644
--- a/apps/website/src/components/base/ScrollbarOverlayContainer.astro
+++ b/apps/website/src/components/base/ScrollbarOverlayContainer.astro
@@ -1,21 +1,21 @@
---
-import type { HTMLAttributes } from "astro/types";
+import type { HTMLAttributes } from 'astro/types';
-interface Props extends HTMLAttributes<"div"> {
+interface Props extends HTMLAttributes<'div'> {
}
const { ...attr } = Astro.props;
---
-<div {...attr}>
- <slot></slot>
-</div>
+ <div {...attr}>
+ <slot></slot>
+ </div>
-<style>
+ <style>
@media (hover: hover) {
div {
-
+
}
div::-webkit-scrollbar {
@@ -48,4 +48,4 @@ const { ...attr } = Astro.props;
background-color: #00000040;
}
}
-</style> \ No newline at end of file
+ </style>
diff --git a/apps/website/src/components/base/Section.astro b/apps/website/src/components/base/Section.astro
index 0d177ef..6ea3075 100644
--- a/apps/website/src/components/base/Section.astro
+++ b/apps/website/src/components/base/Section.astro
@@ -1,38 +1,45 @@
---
-import type { HTMLAttributes } from "astro/types";
+import type { HTMLAttributes } from 'astro/types';
-interface Props extends HTMLAttributes<"section"> {
- maxWidth?: "none" | String;
- colReverse?: boolean;
- wrapperClass?: string;
+interface Props extends HTMLAttributes<'section'> {
+ maxWidth?: 'none' | String
+ colReverse?: boolean
+ wrapperClass?: string
+ wFull?: boolean
+ hFull?: boolean
}
const {
- maxWidth = "1080px",
+ maxWidth = '1024px',
colReverse = true,
- wrapperClass = "",
+ wrapperClass = '',
+ wFull = true,
+ hFull = false,
...props
} = Astro.props;
-const twoColumn = Astro.slots.has("left") || Astro.slots.has("right");
+const twoColumn = Astro.slots.has('left') || Astro.slots.has('right');
-const className = `max-w-[${maxWidth}] w-full px-5 md:p-0 flex gap-4`
- + (twoColumn ? ` ${maxWidth == "none" ? "justify-center" : "justify-between md:justify-evenly lg:justify-between"} ${colReverse ? "flex-col-reverse" : "flex-col"} md:flex-row md:items-center md:flex-row` : "")
- + (props.class ? ` ${props.class}` : "");
+const twoColumnClasses = ` ${maxWidth === 'none' ? 'justify-center' : 'justify-center lg:justify-between'}
+ ${colReverse ? 'flex-col-reverse' : 'flex-col'} lg:flex-row items-center`;
+
+const className = `max-w-[${maxWidth}] ${hFull ? 'min-h-screen' : 'h-auto'} ${wFull ? 'w-full' : `w-[${maxWidth}]`} px-5 xl:px-0 flex gap-x-20 gap-y-4${twoColumn ? twoColumnClasses : ''}${props.class ? ` ${props.class}` : ''}`;
---
-<section class={`w-full flex justify-center${wrapperClass ? ` ${wrapperClass}` : ""}`}>
+<section class={`w-full outline-none flex justify-center ${wrapperClass ?? ''}`}>
<div class={className} {...props}>
- {twoColumn ? (
- <div class="flex flex-col items-start text-left relative">
- <slot name="left"></slot>
- </div>
+ {twoColumn
+ ? (
+ <div class="flex flex-col items-center text-center w-full md:w-auto md:items-start md:text-left relative">
+ <slot name="left"></slot>
+ </div>
- <div class="flex flex-col items-start text-left relative">
- <slot name="right"></slot>
- </div>
- ) : (
- <slot></slot>
- )}
+ <div class="flex flex-col items-center text-center w-full md:w-auto md:items-start md:text-left relative">
+ <slot name="right"></slot>
+ </div>
+ )
+ : (
+ <slot></slot>
+ )}
</div>
</section>
diff --git a/apps/website/src/components/base/Slider.astro b/apps/website/src/components/base/Slider.astro
new file mode 100644
index 0000000..1afd680
--- /dev/null
+++ b/apps/website/src/components/base/Slider.astro
@@ -0,0 +1,73 @@
+---
+import type { HTMLAttributes } from 'astro/types';
+
+interface Props extends HTMLAttributes<'div'> {
+ dir?: string
+ wrapperClass?: string
+ childrenNum: number
+ childrenSize?: string
+ speed?: string
+}
+
+const {
+ dir = 'left',
+ wrapperClass = '',
+ childrenNum,
+ childrenSize = '256px',
+ speed = '25s',
+} = Astro.props;
+
+---
+
+<div class={
+ `w-full slider
+ ${dir === 'right' ? 'reverse' : ''}
+ ${wrapperClass}`
+}>
+ <div class="wrapper flex flex-row gap-2.5">
+ <slot class="content" />
+ <slot class="content" />
+ </div>
+</div>
+
+<!--
+ credit to modrinth's implementation! here is their CSS code:
+ https://github.com/modrinth/knossos/blob/d6ba3f3adfd8f52b85f83e53660d3d87cd0bc9ea/pages/index.vue#L620-L675
+ oh and since theirs is in AGPL, please note that this codeblock is also AGPL
+-->
+<style lang="scss" define:vars={{ childrenNum, childrenSize, speed }}>
+ .slider {
+ .wrapper {
+ animation: var(--speed) linear infinite slide;
+ @media (prefers-reduced-motion) {
+ animation: none;
+ }
+ @keyframes slide {
+ from {
+ transform: translateX(0);
+ }
+ to {
+ transform: translateX(calc((var(--childrenSize) + 10px) * -1 * var(--childrenNum)));
+ }
+ }
+ }
+
+ /**
+ &:hover > .wrapper, &.reverse:hover > .wrapper {
+ animation-play-state: paused;
+ }
+ */
+
+ &.reverse > .wrapper {
+ animation: var(--speed) linear infinite slide-reverse;
+ @keyframes slide-reverse {
+ from {
+ transform: translateX(calc((var(--childrenSize) + 10px) * -1 * var(--childrenNum)));
+ }
+ to {
+ transform: translateX(0);
+ }
+ }
+ }
+ }
+</style>
diff --git a/apps/website/src/components/base/Tag.astro b/apps/website/src/components/base/Tag.astro
index e6fd34f..2eb5778 100644
--- a/apps/website/src/components/base/Tag.astro
+++ b/apps/website/src/components/base/Tag.astro
@@ -1,14 +1,13 @@
---
-import type { HTMLAttributes } from "astro/types";
+import type { HTMLAttributes } from 'astro/types';
-interface Props extends HTMLAttributes<"span"> {}
+interface Props extends HTMLAttributes<'span'> {}
const { ...attr } = Astro.props;
---
-<div class="transition-colors text-blue-500 hover:bg-blue-500/20 text-xs font-medium bg-blue-500/10 rounded-md flex flex-col justify-center items-center px-2 py-0.5">
- <span {...attr}>
- <slot></slot>
- </span>
+<div class="leading-none transition-colors text-blue-500 hover:bg-blue-500/20 text-xs font-medium bg-blue-500/10 rounded-md flex flex-col justify-center items-center px-2 py-0.5">
+ <span {...attr}>
+ <slot></slot>
+ </span>
</div>
-
diff --git a/apps/website/src/components/base/navbar/Navbar.astro b/apps/website/src/components/base/navbar/Navbar.astro
new file mode 100644
index 0000000..8903b7e
--- /dev/null
+++ b/apps/website/src/components/base/navbar/Navbar.astro
@@ -0,0 +1,23 @@
+---
+import type { Config } from '@webtypes/Config';
+import type { HTMLAttributes } from 'astro/types';
+import config from 'config';
+import NavbarElement from '../navbar/NavbarElement.astro';
+
+interface Props extends HTMLAttributes<'div'> {}
+const props = Astro.props;
+---
+<div {...props} class="absolute w-full flex flex-row justify-center h-screen max-h-[110px] px-3 z-navbar text-[16px]">
+ <nav class="w-full max-w-[1024px] flex flex-col md:flex-row justify-between items-center">
+ <ul class="flex flex-row justify-start gap-4 max-md:mt-4">
+ {(config as Config).navbar.left.map((element, index) => (
+ <NavbarElement {element} {index}/>
+ ))}
+ </ul>
+ <ul class="flex flex-row justify-center md:justify-end gap-4 flex-wrap">
+ {(config as Config).navbar.right.map((element, index) => (
+ <NavbarElement {element} {index}/>
+ ))}
+ </ul>
+ </nav>
+</div>
diff --git a/apps/website/src/components/base/navbar/NavbarElement.astro b/apps/website/src/components/base/navbar/NavbarElement.astro
new file mode 100644
index 0000000..5e37253
--- /dev/null
+++ b/apps/website/src/components/base/navbar/NavbarElement.astro
@@ -0,0 +1,100 @@
+---
+import Icon from '@components/icons/Icon.astro';
+import Logo from '@components/logos/Logo.astro';
+import type { LogoType, NavbarElement } from '@webtypes/Config';
+import Header from '../Header.astro';
+import ScreenOverlay from '../ScreenOverlay.astro';
+import ScrollbarOverlayContainer from '../ScrollbarOverlayContainer.astro';
+import Tag from '../Tag.astro';
+
+interface Props {
+ element: NavbarElement
+ index: number
+}
+
+const {
+ element,
+ index,
+} = Astro.props;
+
+function isCurrentPage(url: string): boolean {
+ return Astro.url.pathname === url;
+}
+
+---
+
+ <li class="sm:relative max-sm:overflow-hidden flex flex-row justify-center items-center text-center">
+ {element.path
+? (
+ <a href={element.path} class={`p-2 flex flex-row justify-center items-center hover:text-blue-500 ${isCurrentPage(element.path) ? 'text-blue-400' : 'text-gray-700'}`}>
+ {element.text && element.text}
+ {element.logo && <Logo class="active:scale-95 transition-transform" size={element.logo[1] < 0 ? undefined : element.logo[1]} logo={element.logo[0] as LogoType}/>}
+ {element.dropdown && <Icon icon="chevron-down"/>}
+ </a>
+ )
+: (
+ <label for={`navbar-input-${index}`} class="group">
+ {element.dropdown && (
+ <p class={`p-2 flex flex-row justify-center items-center hover:text-blue-500 cursor-default ${isCurrentPage(element.dropdown[0].path ?? '') ? 'text-blue-400' : 'text-gray-700'}`}>
+ {element.text && element.text}
+ {element.logo && <Logo size={element.logo[1] < 0 ? undefined : element.logo[1]} logo={element.logo[0] as LogoType}/>}
+ {element.dropdown && <Icon icon="chevron-down"/>}
+ </p>
+
+ <ScreenOverlay class="max-sm:group-focus-within:opacity-100 z-navbar-backdrop"/>
+ <input tabindex="-1" type="checkbox" id={`navbar-input-${index}`} class="peer appearance-none absolute"/>
+ <div class={`
+ transition-opacity
+ fixed md:absolute right-0 max-sm:bottom-0
+ max-sm:overflow-hidden
+ max-sm:max-h-[70vh] max-sm:h-screen max-sm:w-screen
+ pointer-events-none opacity-0
+ z-navbar
+
+ md:top-full md:right-0
+
+ group-focus-within:pointer-events-auto group-focus-within:opacity-100
+ md:group-hover:pointer-events-auto md:group-hover:opacity-100
+ focus-within:pointer-events-auto focus-within:opacity-100
+ md:hover:pointer-events-auto md:hover:opacity-100
+ `}>
+ <ScrollbarOverlayContainer
+ tabindex="-1"
+ class={`
+ bg-gray-50
+ border border-gray-100
+ rounded-t-lg md:rounded-lg
+ transition-transform
+ max-sm:translate-y-1/3 max-sm:left-0
+ group-focus-within:translate-y-0
+ max-h-full md:max-h-96 overflow-y-auto min-h-full
+ md:shadow-lg
+ `}>
+ <ul class="p-4">
+ {element.dropdown.map(item => (
+ <li>
+ <a href={item.path} class="flex sm:min-w-[400px] sm:max-w-[400px]">
+ <div class={`transition-[color,background-color,filter] text-left w-full flex flex-row justify-start rounded-md items-center px-6 py-4 gap-6 ${item.path ? 'hover:bg-blue-50 active:bg-blue-100' : 'hover:grayscale hover:brightness-75'}`}>
+ <div class="w-[36px]">
+ {item.logo && <Logo size={40} logo={item.logo}/>}
+ </div>
+
+ <div class="flex flex-col justify-start items-start">
+ <div class="flex flex-row gap-2">
+ <Header inheritSize size="md" class="text-gray-800 text-md md:text-sm font-medium">{item.name}</Header>
+ {item.tag && <Tag class="text-sm md:text-xxs">{item.tag}</Tag>}
+ </div>
+ <p class="text-md md:text-sm text-gray-400 font-light">{item.description}</p>
+ </div>
+ </div>
+ </a>
+ </li>
+ ))}
+ </ul>
+ </ScrollbarOverlayContainer>
+ </div>
+ )}
+ </label>
+)}
+ </li>
+{/* WHY IS ESLINT DOING THIS */}