diff --git a/docusaurus.ts b/docusaurus.ts
index a1811c7..0064510 100644
--- a/docusaurus.ts
+++ b/docusaurus.ts
@@ -16,6 +16,16 @@ export const getConfig = (cfg: LttleDocusaurusConfig): Config => ({
title: "lttle.cloud docs",
tagline: "no rewrites. no cold starts. no paying for idle.",
favicon: "img/favicon.ico",
+ customFields: {
+ brandTitleParts: {
+ lttle: "lttle",
+ dot: ".",
+ cloud: "cloud",
+ suffix: "docs",
+ taglineHtml:
+ "no rewrites. no cold starts. no paying for idle.",
+ },
+ },
// Future flags, see https://docusaurus.io/docs/api/docusaurus-config#future
future: {
diff --git a/src/components/BrowserWindow/styles.module.css b/src/components/BrowserWindow/styles.module.css
index c1d99eb..a9842f9 100644
--- a/src/components/BrowserWindow/styles.module.css
+++ b/src/components/BrowserWindow/styles.module.css
@@ -68,7 +68,9 @@
background-color: var(--ifm-background-color);
color: var(--ifm-color-gray-800);
padding: 5px 15px;
- font: 400 13px Arial, sans-serif;
+ font:
+ 400 13px Arial,
+ sans-serif;
user-select: none;
}
diff --git a/src/components/HomepageFeatures/index.tsx b/src/components/HomepageFeatures/index.tsx
index 31c1c28..f9189b2 100644
--- a/src/components/HomepageFeatures/index.tsx
+++ b/src/components/HomepageFeatures/index.tsx
@@ -9,34 +9,67 @@ type FeatureItem = {
description: ReactNode;
};
-const FeatureList: FeatureItem[] = [
+const FeatureList1: FeatureItem[] = [
{
- title: "Easy to Use",
- Svg: require("@site/static/img/undraw_docusaurus_mountain.svg").default,
+ title: "lightweight",
+ Svg: require("@site/static/img/chunk/folder-open.svg").default,
description: (
<>
- Docusaurus was designed from the ground up to be easily installed and
- used to get your website up and running quickly.
+ lttle.cloud is designed to be lightweight and efficient, with a focus on
+ performance and scalability.
>
),
},
{
- title: "Focus on What Matters",
- Svg: require("@site/static/img/undraw_docusaurus_tree.svg").default,
+ title: "open source",
+ Svg: require("@site/static/img/chunk/door-open.svg").default,
description: (
<>
- Docusaurus lets you focus on your docs, and we'll do the chores. Go
- ahead and move your docs into the docs directory.
+ lttle.cloud is open source, and we're always looking for
+ contributions.
>
),
},
{
- title: "Powered by React",
- Svg: require("@site/static/img/undraw_docusaurus_react.svg").default,
+ title: "simple",
+ Svg: require("@site/static/img/chunk/checkmark.svg").default,
description: (
<>
- Extend or customize your website layout by reusing React. Docusaurus can
- be extended while reusing the same header and footer.
+ lttle.cloud is designed to be simple and easy to use, with a focus on
+ usability and accessibility.
+ >
+ ),
+ },
+];
+
+const FeatureList2: FeatureItem[] = [
+ {
+ title: "secure",
+ Svg: require("@site/static/img/chunk/shield-check.svg").default,
+ description: (
+ <>
+ lttle.cloud is designed to be secure and reliable, with a focus on
+ security and reliability.
+ >
+ ),
+ },
+ {
+ title: "community",
+ Svg: require("@site/static/img/chunk/users.svg").default,
+ description: (
+ <>
+ lttle.cloud is designed to be high performance, with a focus on
+ performance and scalability.
+ >
+ ),
+ },
+ {
+ title: "high performance",
+ Svg: require("@site/static/img/chunk/arrow-trend-up.svg").default,
+ description: (
+ <>
+ lttle.cloud is designed to be high performance, with a focus on
+ performance and scalability.
>
),
},
@@ -44,14 +77,10 @@ const FeatureList: FeatureItem[] = [
function Feature({ title, Svg, description }: FeatureItem) {
return (
-
-
-
-
-
-
{title}
-
{description}
-
+
+
+
{title}
+
{description}
);
}
@@ -59,11 +88,28 @@ function Feature({ title, Svg, description }: FeatureItem) {
export default function HomepageFeatures(): ReactNode {
return (
-
-
- {FeatureList.map((props, idx) => (
-
- ))}
+
+
+
+
key features
+
grows with you, not against you
+
+
+ {FeatureList1.map((props, idx) => (
+
+ ))}
+
+
+
+
+
why lttle.cloud
+
we keep things running, you keep moving
+
+
+ {FeatureList2.map((props, idx) => (
+
+ ))}
+
diff --git a/src/components/HomepageFeatures/styles.module.css b/src/components/HomepageFeatures/styles.module.css
index b248eb2..7d88ff5 100644
--- a/src/components/HomepageFeatures/styles.module.css
+++ b/src/components/HomepageFeatures/styles.module.css
@@ -1,11 +1,118 @@
.features {
display: flex;
+ flex-direction: column;
align-items: center;
- padding: 2rem 0;
+
+ gap: 1rem;
+ padding: 4rem 0;
width: 100%;
+ background-color: var(--ifm-landing-page-section-background-color);
+}
+
+.featuresContainer {
+ max-width: 1200px;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 4rem;
+ padding: 0 1rem;
+}
+
+.featuresSection {
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+}
+
+.featuresHeader {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+ text-align: center;
+
+ h2 {
+ font-size: 2.25rem;
+ margin: 0;
+ color: var(--ifm-font-color-base);
+ }
+
+ p {
+ font-size: 1rem;
+ margin: 0;
+ color: var(--ifm-font-color-secondary);
+ line-height: 1.2;
+ }
+}
+
+.featuresRow {
+ display: flex;
+ gap: 1rem;
+}
+
+.featureCard {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ gap: 1rem;
+ padding: 1.5rem;
+ border-radius: 1rem;
+
+ box-shadow: var(--ifm-landing-page-feature-card-box-shadow);
+
+ background-color: var(--ifm-landing-page-feature-card-background-color);
+}
+
+.featureCard h2 {
+ font-size: 1.5rem;
+ margin: 0;
+ color: var(--ifm-font-color-base);
+}
+
+.featureCard p {
+ font-size: 1rem;
+ margin: 0;
+ color: var(--ifm-font-color-secondary);
}
.featureSvg {
- height: 200px;
- width: 200px;
+ height: 64px;
+ width: 64px;
+}
+
+@media screen and (max-width: 768px) {
+ .features {
+ padding: 2rem 0;
+ }
+
+ .featuresHeader {
+ h2 {
+ font-size: 1.5rem;
+ }
+
+ p {
+ font-size: 0.875rem;
+ }
+ }
+
+ .featuresRow {
+ flex-direction: column;
+ }
+
+ .featureCard {
+ padding: 1rem;
+
+ h2 {
+ font-size: 1.25rem;
+ }
+
+ p {
+ font-size: 0.875rem;
+ }
+ }
+
+ .featureSvg {
+ height: 32px;
+ width: 32px;
+ }
}
diff --git a/src/components/HomepageSocials/index.tsx b/src/components/HomepageSocials/index.tsx
new file mode 100644
index 0000000..d871917
--- /dev/null
+++ b/src/components/HomepageSocials/index.tsx
@@ -0,0 +1,60 @@
+import Heading from "@theme/Heading";
+import type { ReactNode } from "react";
+import styles from "./styles.module.css";
+import clsx from "clsx";
+
+type SocialItem = {
+ title: string;
+ Svg: React.ComponentType
>;
+ href: string;
+};
+
+const socials: SocialItem[] = [
+ {
+ title: "GitHub",
+ Svg: require("@site/static/img/social-media/github.svg").default,
+ href: "https://github.com/lttle-cloud/ignition",
+ },
+ {
+ title: "Discord",
+ Svg: require("@site/static/img/social-media/discord.svg").default,
+ href: "https://discord.gg/xhNGGrZQja",
+ },
+ {
+ title: "LinkedIn",
+ Svg: require("@site/static/img/social-media/linkedin.svg").default,
+ href: "https://www.linkedin.com/company/lttle-cloud",
+ },
+];
+
+function SocialCard({ title, Svg, href }: SocialItem) {
+ return (
+
+
+ {title}
+
+ );
+}
+
+export default function HomepageSocials(): ReactNode {
+ return (
+
+
+
+
join the community
+
Connect with other developers and get help when you need it.
+
+
+ {socials.map((s, i) => (
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/HomepageSocials/styles.module.css b/src/components/HomepageSocials/styles.module.css
new file mode 100644
index 0000000..3869b8a
--- /dev/null
+++ b/src/components/HomepageSocials/styles.module.css
@@ -0,0 +1,123 @@
+.socialsSection {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+
+ gap: 1rem;
+ padding: 4rem 0;
+ width: 100%;
+ background-color: var(--ifm-background-color);
+
+ .header {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1rem;
+
+ h2 {
+ font-size: 2.25rem;
+ margin: 0;
+ color: var(--ifm-font-color-base);
+ }
+
+ p {
+ font-size: 1rem;
+ margin: 0;
+ color: var(--ifm-font-color-secondary);
+ line-height: 1.2;
+ }
+ }
+
+ .container {
+ max-width: 1200px;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ gap: 2rem;
+ padding: 0 1rem;
+ }
+
+ .cardsRow {
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+
+ .socialCard {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 1.5rem 2rem;
+ border-radius: 1rem;
+ text-decoration: none;
+ width: 195px;
+
+ background-color: var(--ifm-landing-page-section-background-color);
+ box-shadow: var(--ifm-landing-page-feature-card-box-shadow);
+
+ .socialIcon {
+ height: 48px;
+ width: 48px;
+
+ path {
+ transition: all 0.2s ease-in-out;
+ }
+ }
+
+ .socialTitle {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: var(--ifm-font-color-base);
+ }
+
+ &:global(.github):hover {
+ .socialIcon {
+ path {
+ fill: var(--ifm-color-gray-900);
+ }
+ }
+ }
+
+ &:global(.discord):hover {
+ .socialIcon {
+ path {
+ fill: var(--color-purple-2);
+ }
+ }
+ }
+
+ &:global(.linkedin):hover {
+ .socialIcon {
+ path {
+ fill: var(--color-blue-2);
+ }
+ }
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .socialsSection {
+ padding: 3rem 1rem;
+
+ .header {
+ h2 {
+ font-size: 2rem;
+ }
+ }
+
+ .cardsRow {
+ flex-wrap: wrap;
+
+ .socialCard {
+ width: 130px;
+
+ .socialTitle {
+ font-size: 1.25rem;
+ }
+ }
+ }
+ }
+}
diff --git a/src/css/custom.css b/src/css/custom.css
index 393c9d3..a771562 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -6,27 +6,156 @@
/* You can override the default Infima variables here. */
:root {
- --ifm-color-primary: #4498b3;
- --ifm-color-primary-dark: #347493;
- --ifm-color-primary-darker: #277148;
- --ifm-color-primary-darkest: #205d3b;
- --ifm-color-primary-light: #33925d;
- --ifm-color-primary-lighter: #359962;
- --ifm-color-primary-lightest: #3cad6e;
+ --color-pink-0: #ffe8e8;
+ --color-pink-1: #ffcfcf;
+ --color-pink-2: #fcb1b1;
+ --color-pink-3: #ee8787;
+ --color-pink-4: #d04a4a;
+ --color-pink-5: #a42f2f;
+ --color-pink-6: #731414;
+
+ --color-red-1: #ff8b7e;
+ --color-red-2: #f24836;
+ --color-red-3: #b42011;
+
+ --color-orange-1: #ffaf60;
+ --color-orange-2: #ea9847;
+ --color-orange-3: #d4742f;
+
+ --color-yellow-1: #ffe77d;
+ --color-yellow-2: #f5d547;
+ --color-yellow-3: #e4b532;
+
+ --color-green-1: #d2e79b;
+ --color-green-2: #b1c971;
+ --color-green-3: #90aa5a;
+
+ --color-purple-1: #ecc9f2;
+ --color-purple-2: #d7a6e0;
+ --color-purple-3: #b57bbf;
+
+ --color-blue-0: #cfe3fb;
+ --color-blue-1: #9ebfe9;
+ --color-blue-2: #6798d5;
+ --color-blue-3: #3e6da7;
+ --color-blue-4: #214776;
+ --color-blue-5: #0d2037;
+ --color-blue-6: #071729;
+
+ --color-gray-0: #fbfcfe;
+ --color-gray-1: #f7f8fd;
+ --color-gray-2: #f3f3f4;
+ --color-gray-3: #e1e4eb;
+ --color-gray-4: #b4bcd1;
+ --color-gray-5: #8a94ac;
+ --color-gray-6: #69748f;
+
+ --color-black-1: #3d4457;
+ --color-black-1-5: #2e3340;
+ --color-black-2: #181b23;
+ --color-black-3: #05070e;
+
+ --color-teal-0: #e8f7fc;
+ --color-teal-1: #acdfee;
+ --color-teal-2: #78c7dd;
+ --color-teal-3: #419bb4;
+ --color-teal-4: #347493;
+ --color-teal-5: #154a65;
+ --color-teal-6: #082c3f;
+
+ --ifm-color-gray-100: var(--color-gray-0);
+ --ifm-color-gray-200: var(--color-gray-1);
+ --ifm-color-gray-300: var(--color-gray-2);
+ --ifm-color-gray-400: var(--color-gray-3);
+ --ifm-color-gray-500: var(--color-gray-4);
+ --ifm-color-gray-600: var(--color-gray-5);
+ --ifm-color-gray-700: var(--color-gray-6);
+ --ifm-color-gray-800: var(--color-black-1);
+ --ifm-color-gray-850: var(--color-black-1-5);
+ --ifm-color-gray-900: var(--color-black-2);
+
+ --ifm-color-primary: var(--color-pink-3);
+ --ifm-color-primary-dark: var(--color-pink-4);
+ --ifm-color-primary-darker: var(--color-pink-5);
+ --ifm-color-primary-darkest: var(--color-pink-6);
+ --ifm-color-primary-light: var(--color-pink-2);
+ --ifm-color-primary-lighter: var(--color-pink-1);
+ --ifm-color-primary-lightest: var(--color-pink-0);
+
+ --ifm-color-secondary: var(--color-gray-3);
+
+ --ifm-color-secondary-dark: var(--color-gray-4);
+ --ifm-color-secondary-darker: var(--color-gray-5);
+ --ifm-color-secondary-darkest: var(--color-gray-6);
+ --ifm-color-secondary-light: var(--color-gray-2);
+ --ifm-color-secondary-lighter: var(--color-gray-1);
+ --ifm-color-secondary-lightest: var(--color-gray-0);
+
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
+
+ --ifm-button-background-color: var(--color-pink-3);
+
+ --ifm-border-radius: 1rem;
+ --ifm-button-border-radius: 1rem;
+
+ --ifm-landing-page-section-background-color: var(--ifm-color-gray-200);
+ --ifm-landing-page-feature-card-background-color: white;
+ --ifm-landing-page-feature-card-box-shadow: 8px 8px 0 0
+ var(--ifm-color-gray-400);
+
+ .button {
+ transition: all 0.1s ease-in-out;
+ box-shadow: 5px 5px 0 0 var(--color-black-2);
+ }
+
+ .button:hover,
+ .button--primary:hover,
+ .button--secondary:hover,
+ .button--outline:hover {
+ transform: translate(3px, 3px);
+ box-shadow: 3px 3px 0 0 var(--color-black-2);
+ }
+
+ .button:active,
+ .button--primary:active,
+ .button--secondary:active,
+ .button--outline:active {
+ transform: translate(5px, 5px);
+ box-shadow: 1px 1px 0 0 var(--color-black-2);
+ }
+
+ --ifm-font-family-base: "Onest", sans-serif;
+ --ifm-heading-font-family: "Onest", sans-serif;
+}
+
+::selection {
+ background: var(--color-teal-3);
+ color: #ffffff;
+}
+::-moz-selection {
+ background: var(--color-teal-3);
+ color: #ffffff;
}
/* For readability concerns, you should choose a lighter palette in dark mode. */
[data-theme="dark"] {
- --ifm-color-primary: #419bb4;
- --ifm-color-primary-dark: #21af90;
- --ifm-color-primary-darker: #1fa588;
- --ifm-color-primary-darkest: #1a8870;
- --ifm-color-primary-light: #29d5b0;
- --ifm-color-primary-lighter: #32d8b4;
- --ifm-color-primary-lightest: #4fddbf;
+ --ifm-color-primary: var(--color-pink-3);
+ --ifm-color-primary-dark: var(--color-pink-4);
+ --ifm-color-primary-darker: var(--color-pink-5);
+ --ifm-color-primary-darkest: var(--color-pink-6);
+ --ifm-color-primary-light: var(--color-pink-2);
+ --ifm-color-primary-lighter: var(--color-pink-1);
+ --ifm-color-primary-lightest: var(--color-pink-0);
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
+
+ --ifm-font-family-base: "Onest", sans-serif;
+ --ifm-heading-font-family: "Onest", sans-serif;
+
+ --ifm-landing-page-section-background-color: var(--ifm-color-gray-850);
+ --ifm-landing-page-feature-card-background-color: var(--ifm-color-gray-800);
+ --ifm-landing-page-feature-card-box-shadow: 8px 8px 0 0
+ var(--ifm-color-gray-700);
}
.code-block-error-line {
diff --git a/src/pages/index.module.css b/src/pages/index.module.css
index 9f71a5d..f1b8644 100644
--- a/src/pages/index.module.css
+++ b/src/pages/index.module.css
@@ -5,19 +5,126 @@
.heroBanner {
padding: 4rem 0;
+ display: flex;
+ gap: 4rem;
text-align: center;
+ align-items: center;
+ justify-content: center;
position: relative;
overflow: hidden;
+
+ background-color: var(--ifm-background-color);
}
-@media screen and (max-width: 996px) {
- .heroBanner {
- padding: 2rem;
+.heroBannerCode {
+ background-color: var(--ifm-color-gray-900);
+ padding: 0.5rem 1rem;
+ border-radius: 0.5rem;
+ border: 1px solid var(--ifm-color-gray-500);
+ color: white;
+
+ .green {
+ color: var(--color-green-2);
+ }
+
+ .purpleItalic {
+ color: var(--color-purple-2);
+ font-style: italic;
+ }
+
+ .blue {
+ color: var(--color-blue-3);
}
}
-.buttons {
+.heroBannerContent {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: left;
+ gap: 2rem;
+
+ h1,
+ p {
+ margin: 0;
+ }
+}
+
+.heroBannerImage {
display: flex;
align-items: center;
justify-content: center;
+
+ svg {
+ width: auto;
+ height: auto;
+ }
+}
+
+.buttons {
+ display: flex;
+}
+
+.brandTitle {
+ display: inline-flex;
+ align-items: baseline;
+ gap: 1rem;
+ color: var(--ifm-font-color-base);
+ font-weight: 500;
+ font-size: 56px;
+
+ .brandTitleParts {
+ display: inline-flex;
+ align-items: baseline;
+ font-weight: 900;
+ }
+
+ .brandLttle {
+ color: var(--ifm-color-primary);
+ }
+
+ .brandDot {
+ color: var(--ifm-color-gray-600);
+ }
+
+ .brandCloud {
+ color: var(--ifm-color-emphasis-900);
+ }
+}
+
+.brandTagline {
+ color: var(--ifm-font-color-base);
+ font-weight: 500;
+ font-size: 1.5rem;
+ line-height: 1.2;
+}
+
+@media screen and (max-width: 996px) {
+ .heroBanner {
+ padding: 2rem;
+ gap: 2rem;
+
+ svg {
+ max-width: 100%;
+ }
+ }
+
+ .heroBannerContent {
+ gap: 1rem;
+ }
+
+ .brandTitle {
+ font-size: 32px;
+ }
+
+ .brandTagline {
+ font-size: 1rem;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .heroBanner {
+ flex-direction: column-reverse;
+ gap: 2rem;
+ }
}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 2a45864..eabd28a 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -5,24 +5,63 @@ import Heading from "@theme/Heading";
import Layout from "@theme/Layout";
import clsx from "clsx";
import type { ReactNode } from "react";
+import HeroImage from "@site/static/img/hero-illustration.svg";
+import HomepageSocials from "@site/src/components/HomepageSocials";
import styles from "./index.module.css";
function HomepageHeader() {
const { siteConfig } = useDocusaurusContext();
+ const brand = (siteConfig.customFields as any)?.brandTitleParts as
+ | {
+ lttle: string;
+ dot: string;
+ cloud: string;
+ suffix: string;
+ taglineHtml: string;
+ }
+ | undefined;
return (
-
-
- {siteConfig.title}
+
+
+ {brand ? (
+ <>
+
+
+ {brand.lttle}
+ {brand.dot}
+ {brand.cloud}
+
+ {brand.suffix}
+
+ >
+ ) : (
+ siteConfig.title
+ )}
-
{siteConfig.tagline}
+
+
+ curl {" "}
+ -fsSL {" "}
+ https://install.lttle.sh | {" "}
+ bash
+
-
- Docusaurus Tutorial - 5min ⏱️
+
+ start now
+
+
+
+
);
}
@@ -34,6 +73,7 @@ export default function Home(): ReactNode {
+
);
diff --git a/src/theme/Footer/Copyright/index.tsx b/src/theme/Footer/Copyright/index.tsx
new file mode 100644
index 0000000..508da70
--- /dev/null
+++ b/src/theme/Footer/Copyright/index.tsx
@@ -0,0 +1,13 @@
+import React, { type ReactNode } from "react";
+import type { Props } from "@theme/Footer/Copyright";
+
+export default function FooterCopyright({ copyright }: Props): ReactNode {
+ return (
+
+ );
+}
diff --git a/src/theme/Footer/Layout/index.tsx b/src/theme/Footer/Layout/index.tsx
new file mode 100644
index 0000000..133c8ca
--- /dev/null
+++ b/src/theme/Footer/Layout/index.tsx
@@ -0,0 +1,70 @@
+import React, { useEffect, useState, type ReactNode } from "react";
+import clsx from "clsx";
+import { ThemeClassNames } from "@docusaurus/theme-common";
+import type { Props } from "@theme/Footer/Layout";
+import FooterLogo from "@site/static/img/footer-logo.svg";
+import styles from "./styles.module.css";
+
+export default function FooterLayout({
+ style,
+ links,
+ logo,
+ copyright,
+}: Props): ReactNode {
+ const [windowWidth, setWindowWidth] = useState(0);
+ const logoHeight = windowWidth * 0.13;
+
+ useEffect(() => {
+ setWindowWidth(window.innerWidth);
+
+ const handleResize = () => {
+ setWindowWidth(window.innerWidth);
+ };
+ window.addEventListener("resize", handleResize);
+ return () => window.removeEventListener("resize", handleResize);
+ }, []);
+
+ return (
+
+ );
+}
diff --git a/src/theme/Footer/Layout/styles.module.css b/src/theme/Footer/Layout/styles.module.css
new file mode 100644
index 0000000..dc866bd
--- /dev/null
+++ b/src/theme/Footer/Layout/styles.module.css
@@ -0,0 +1,28 @@
+.footer {
+ display: flex;
+ flex-direction: column;
+ gap: 3rem;
+
+ overflow: hidden;
+ width: 100%;
+ max-width: 100vw;
+ padding-bottom: 0;
+}
+
+.footerLogoContainer {
+ height: 300px;
+ position: relative;
+ overflow: visible;
+
+ svg {
+ position: absolute;
+
+ &:first-child {
+ left: -50%;
+ }
+
+ &:last-child {
+ right: -50%;
+ }
+ }
+}
diff --git a/src/theme/Footer/LinkItem/index.tsx b/src/theme/Footer/LinkItem/index.tsx
new file mode 100644
index 0000000..c0dfe6e
--- /dev/null
+++ b/src/theme/Footer/LinkItem/index.tsx
@@ -0,0 +1,30 @@
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Link from "@docusaurus/Link";
+import useBaseUrl from "@docusaurus/useBaseUrl";
+import isInternalUrl from "@docusaurus/isInternalUrl";
+import IconExternalLink from "@theme/Icon/ExternalLink";
+import type { Props } from "@theme/Footer/LinkItem";
+
+export default function FooterLinkItem({ item }: Props): ReactNode {
+ const { to, href, label, prependBaseUrlToHref, className, ...props } = item;
+ const toUrl = useBaseUrl(to);
+ const normalizedHref = useBaseUrl(href, { forcePrependBaseUrl: true });
+
+ return (
+
+ {label}
+ {href && !isInternalUrl(href) && }
+
+ );
+}
diff --git a/src/theme/Footer/Links/MultiColumn/index.tsx b/src/theme/Footer/Links/MultiColumn/index.tsx
new file mode 100644
index 0000000..f1fc498
--- /dev/null
+++ b/src/theme/Footer/Links/MultiColumn/index.tsx
@@ -0,0 +1,52 @@
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import { ThemeClassNames } from "@docusaurus/theme-common";
+import LinkItem from "@theme/Footer/LinkItem";
+import type { Props } from "@theme/Footer/Links/MultiColumn";
+
+type ColumnType = Props["columns"][number];
+type ColumnItemType = ColumnType["items"][number];
+
+function ColumnLinkItem({ item }: { item: ColumnItemType }) {
+ return item.html ? (
+
+ ) : (
+
+
+
+ );
+}
+
+function Column({ column }: { column: ColumnType }) {
+ return (
+
+
{column.title}
+
+ {column.items.map((item, i) => (
+
+ ))}
+
+
+ );
+}
+
+export default function FooterLinksMultiColumn({ columns }: Props): ReactNode {
+ return (
+
+ {columns.map((column, i) => (
+
+ ))}
+
+ );
+}
diff --git a/src/theme/Footer/Links/Simple/index.tsx b/src/theme/Footer/Links/Simple/index.tsx
new file mode 100644
index 0000000..fc4f2ec
--- /dev/null
+++ b/src/theme/Footer/Links/Simple/index.tsx
@@ -0,0 +1,36 @@
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import LinkItem from "@theme/Footer/LinkItem";
+import type { Props } from "@theme/Footer/Links/Simple";
+
+function Separator() {
+ return · ;
+}
+
+function SimpleLinkItem({ item }: { item: Props["links"][number] }) {
+ return item.html ? (
+
+ ) : (
+
+ );
+}
+
+export default function FooterLinksSimple({ links }: Props): ReactNode {
+ return (
+
+
+ {links.map((item, i) => (
+
+
+ {links.length !== i + 1 && }
+
+ ))}
+
+
+ );
+}
diff --git a/src/theme/Footer/Links/index.tsx b/src/theme/Footer/Links/index.tsx
new file mode 100644
index 0000000..76bd9f4
--- /dev/null
+++ b/src/theme/Footer/Links/index.tsx
@@ -0,0 +1,14 @@
+import React, { type ReactNode } from "react";
+
+import { isMultiColumnFooterLinks } from "@docusaurus/theme-common";
+import FooterLinksMultiColumn from "@theme/Footer/Links/MultiColumn";
+import FooterLinksSimple from "@theme/Footer/Links/Simple";
+import type { Props } from "@theme/Footer/Links";
+
+export default function FooterLinks({ links }: Props): ReactNode {
+ return isMultiColumnFooterLinks(links) ? (
+
+ ) : (
+
+ );
+}
diff --git a/src/theme/Footer/Logo/index.tsx b/src/theme/Footer/Logo/index.tsx
new file mode 100644
index 0000000..2aa257a
--- /dev/null
+++ b/src/theme/Footer/Logo/index.tsx
@@ -0,0 +1,40 @@
+import React, { type ReactNode } from "react";
+import clsx from "clsx";
+import Link from "@docusaurus/Link";
+import { useBaseUrlUtils } from "@docusaurus/useBaseUrl";
+import ThemedImage from "@theme/ThemedImage";
+import type { Props } from "@theme/Footer/Logo";
+
+import styles from "./styles.module.css";
+
+function LogoImage({ logo }: Props) {
+ const { withBaseUrl } = useBaseUrlUtils();
+ const sources = {
+ light: withBaseUrl(logo.src),
+ dark: withBaseUrl(logo.srcDark ?? logo.src),
+ };
+ return (
+
+ );
+}
+
+export default function FooterLogo({ logo }: Props): ReactNode {
+ return logo.href ? (
+
+
+
+ ) : (
+
+ );
+}
diff --git a/src/theme/Footer/Logo/styles.module.css b/src/theme/Footer/Logo/styles.module.css
new file mode 100644
index 0000000..faf0e60
--- /dev/null
+++ b/src/theme/Footer/Logo/styles.module.css
@@ -0,0 +1,9 @@
+.footerLogoLink {
+ opacity: 0.5;
+ transition: opacity var(--ifm-transition-fast)
+ var(--ifm-transition-timing-default);
+}
+
+.footerLogoLink:hover {
+ opacity: 1;
+}
diff --git a/src/theme/Footer/index.tsx b/src/theme/Footer/index.tsx
new file mode 100644
index 0000000..a7862df
--- /dev/null
+++ b/src/theme/Footer/index.tsx
@@ -0,0 +1,26 @@
+import React, { type ReactNode } from "react";
+
+import { useThemeConfig } from "@docusaurus/theme-common";
+import FooterLinks from "@theme/Footer/Links";
+import FooterLogo from "@theme/Footer/Logo";
+import FooterCopyright from "@theme/Footer/Copyright";
+import FooterLayout from "@theme/Footer/Layout";
+
+function Footer(): ReactNode {
+ const { footer } = useThemeConfig();
+ if (!footer) {
+ return null;
+ }
+ const { copyright, links, logo, style } = footer;
+
+ return (
+ 0 && }
+ logo={logo && }
+ copyright={copyright && }
+ />
+ );
+}
+
+export default React.memo(Footer);
diff --git a/src/theme/prism-include-languages.ts b/src/theme/prism-include-languages.ts
index f164b2a..825fee4 100644
--- a/src/theme/prism-include-languages.ts
+++ b/src/theme/prism-include-languages.ts
@@ -3,7 +3,7 @@ import type * as PrismNamespace from "prismjs";
import type { Optional } from "utility-types";
export default function prismIncludeLanguages(
- PrismObject: typeof PrismNamespace
+ PrismObject: typeof PrismNamespace,
): void {
const {
themeConfig: { prism },
@@ -41,7 +41,7 @@ export default function prismIncludeLanguages(
/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while|deploy|login|machine|service|svc|namespace|ns|volume|certificate|cert)(?=$|[)\s;|&])/;
} else {
console.error(
- "Could not add our custom functions & keywords to prismjs bash component"
+ "Could not add our custom functions & keywords to prismjs bash component",
);
}
diff --git a/static/img/chunk/arrow-trend-up.svg b/static/img/chunk/arrow-trend-up.svg
new file mode 100644
index 0000000..abf042f
--- /dev/null
+++ b/static/img/chunk/arrow-trend-up.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/img/chunk/checkmark.svg b/static/img/chunk/checkmark.svg
new file mode 100644
index 0000000..af02baf
--- /dev/null
+++ b/static/img/chunk/checkmark.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/img/chunk/door-open.svg b/static/img/chunk/door-open.svg
new file mode 100644
index 0000000..524cb4f
--- /dev/null
+++ b/static/img/chunk/door-open.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/img/chunk/folder-open.svg b/static/img/chunk/folder-open.svg
new file mode 100644
index 0000000..04e6853
--- /dev/null
+++ b/static/img/chunk/folder-open.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/img/chunk/shield-check.svg b/static/img/chunk/shield-check.svg
new file mode 100644
index 0000000..72b7783
--- /dev/null
+++ b/static/img/chunk/shield-check.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/img/chunk/users.svg b/static/img/chunk/users.svg
new file mode 100644
index 0000000..6672172
--- /dev/null
+++ b/static/img/chunk/users.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/static/img/footer-logo.svg b/static/img/footer-logo.svg
new file mode 100644
index 0000000..a3d3b56
--- /dev/null
+++ b/static/img/footer-logo.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/img/hero-illustration.svg b/static/img/hero-illustration.svg
new file mode 100644
index 0000000..b04b8f8
--- /dev/null
+++ b/static/img/hero-illustration.svg
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/img/social-media/discord.svg b/static/img/social-media/discord.svg
new file mode 100644
index 0000000..d12cbe8
--- /dev/null
+++ b/static/img/social-media/discord.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/static/img/social-media/github.svg b/static/img/social-media/github.svg
new file mode 100644
index 0000000..d72c282
--- /dev/null
+++ b/static/img/social-media/github.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/static/img/social-media/linkedin.svg b/static/img/social-media/linkedin.svg
new file mode 100644
index 0000000..22633ae
--- /dev/null
+++ b/static/img/social-media/linkedin.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+