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 ( +
+
+ {links} + {(logo || copyright) && ( +
+ {logo &&
{logo}
} + {copyright} +
+ )} +
+
+ + +
+
+ ); +} 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 @@ + + + + + + + + + +