From 2820a5b541076e23f4eab5a7582d222674993d30 Mon Sep 17 00:00:00 2001 From: Vitaliy Kukharik Date: Tue, 30 Jun 2026 00:31:10 +0200 Subject: [PATCH] Add dark theme for landing page --- src/components/ArchDiagramSection/index.js | 2 + .../ArchDiagramSection/styles.module.css | 6 +- src/components/CLISection/styles.module.css | 4 +- src/components/SocialProofSection/index.js | 56 +++++++++---------- .../SocialProofSection/styles.module.css | 5 +- src/components/TrustedByCarousel/index.js | 49 +++++++++++----- .../TrustedByCarousel/styles.module.css | 25 +++++++++ .../ValuePropsSection/styles.module.css | 4 +- src/css/custom.css | 33 +++++++++++ src/theme/Footer/index.js | 25 ++++++++- src/theme/Footer/styles.module.css | 55 +++++++++++++++++- src/theme/Navbar/styles.module.css | 15 ++++- 12 files changed, 223 insertions(+), 56 deletions(-) diff --git a/src/components/ArchDiagramSection/index.js b/src/components/ArchDiagramSection/index.js index eeed05a..18df282 100644 --- a/src/components/ArchDiagramSection/index.js +++ b/src/components/ArchDiagramSection/index.js @@ -150,6 +150,8 @@ function DiagramInner() { Maintenance | Scaling + | + Monitoring diff --git a/src/components/ArchDiagramSection/styles.module.css b/src/components/ArchDiagramSection/styles.module.css index 0509c20..7bd62cb 100644 --- a/src/components/ArchDiagramSection/styles.module.css +++ b/src/components/ArchDiagramSection/styles.module.css @@ -1,10 +1,10 @@ /* ─── Section — full viewport width ──────────────────────────────── */ .section { - --diagram-line: #8f8f8f; - --diagram-border: #b7b7b7; + --diagram-line: var(--color-diagram-line, #8f8f8f); + --diagram-border: var(--color-diagram-border, #b7b7b7); width: 100vw; min-height: 100vh; - background: var(--color-surface); + background: var(--color-bg); border-bottom: 1px solid var(--color-border); display: flex; align-items: center; diff --git a/src/components/CLISection/styles.module.css b/src/components/CLISection/styles.module.css index a39ab08..a59ea25 100644 --- a/src/components/CLISection/styles.module.css +++ b/src/components/CLISection/styles.module.css @@ -111,7 +111,7 @@ outline: 1.5px solid transparent; outline-offset: 0px; background: transparent; - box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.05); + box-shadow: 6px 6px 0 var(--shadow-pixel); text-decoration: none; transition: border-color 0.18s ease, outline-color 0.18s ease, background 0.18s ease, @@ -139,7 +139,7 @@ background: var(--color-surface); opacity: 1; transform: translate(3px, 3px); - box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1); + box-shadow: 3px 3px 0 var(--shadow-pixel-hover); } .ctaArrow { diff --git a/src/components/SocialProofSection/index.js b/src/components/SocialProofSection/index.js index 606542a..5ce4568 100644 --- a/src/components/SocialProofSection/index.js +++ b/src/components/SocialProofSection/index.js @@ -5,30 +5,30 @@ function CalendarWithClockIcon() { return ( ); } @@ -37,16 +37,16 @@ function StopwatchIcon() { return (
diff --git a/src/components/SocialProofSection/styles.module.css b/src/components/SocialProofSection/styles.module.css index 2cd8d02..a29bceb 100644 --- a/src/components/SocialProofSection/styles.module.css +++ b/src/components/SocialProofSection/styles.module.css @@ -21,7 +21,7 @@ border: 1px solid var(--color-border); border-radius: 2px; background: var(--color-bg); - box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.05); + box-shadow: 8px 8px 0 var(--shadow-pixel); transition: border-color 0.16s ease, box-shadow 0.16s ease; @@ -29,7 +29,7 @@ .banner:hover { border-color: var(--color-primary); - box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.1); + box-shadow: 10px 10px 0 var(--shadow-pixel-hover); } /* ─── Text block ──────────────────────────────────────────────────── */ @@ -72,6 +72,7 @@ align-items: center; gap: 28px; flex-shrink: 0; + color: var(--color-text); } .timeBlock { diff --git a/src/components/TrustedByCarousel/index.js b/src/components/TrustedByCarousel/index.js index a54f67a..ef1736b 100644 --- a/src/components/TrustedByCarousel/index.js +++ b/src/components/TrustedByCarousel/index.js @@ -2,21 +2,32 @@ import React from 'react'; import styles from './styles.module.css'; const sponsors = [ - { name: 'Axiom', img: '/img/sponsors/axiom.png', href: 'https://axiom.trade' }, - { name: 'Awarebuildings', img: '/img/sponsors/awarebuildings.png', href: 'https://www.awarebuildings.com' }, - { name: 'Antistock', img: '/img/sponsors/antistock.png', href: 'https://antistock.io' }, - { name: 'Codefloe', img: '/img/sponsors/codefloe.png', href: 'https://codefloe.com' }, - { name: 'Edclub', img: '/img/sponsors/edclub.png', href: 'https://www.edclub.com' }, - { name: 'Fera', img: '/img/sponsors/fera.png', href: 'https://fera.ai' }, - { name: 'GS Labs', img: '/img/sponsors/gs-labs.png', href: 'https://gs-labs.ru' }, - { name: 'New Byte', img: '/img/sponsors/newbyte.png', href: 'https://newbyte.net.br' }, - { name: 'Optiwise', img: '/img/sponsors/optiwise.png', href: 'https://optiwise.nl' }, - { name: 'Postgres.AI', img: '/img/sponsors/postgresai.png', href: 'https://postgres.ai' }, + { name: 'Axiom', img: '/img/sponsors/axiom.png', darkImg: '/img/sponsors/axiom.dark.png', href: 'https://axiom.trade' }, + { name: 'Awarebuildings', img: '/img/sponsors/awarebuildings.png', darkImg: '/img/sponsors/awarebuildings.dark.png', href: 'https://www.awarebuildings.com' }, + { name: 'Antistock', img: '/img/sponsors/antistock.png', darkImg: '/img/sponsors/antistock.dark.png', href: 'https://antistock.io' }, + { name: 'Codefloe', img: '/img/sponsors/codefloe.png', darkImg: '/img/sponsors/codefloe.dark.png', href: 'https://codefloe.com' }, + { name: 'Edclub', img: '/img/sponsors/edclub.png', darkImg: '/img/sponsors/edclub.dark.png', href: 'https://www.edclub.com' }, + { name: 'Fera', img: '/img/sponsors/fera.png', darkImg: '/img/sponsors/fera.dark.png', href: 'https://fera.ai' }, + { name: 'GS Labs', img: '/img/sponsors/gs-labs.png', darkImg: '/img/sponsors/gs-labs.dark.png', href: 'https://gs-labs.ru' }, + { name: 'New Byte', img: '/img/sponsors/newbyte.png', darkImg: '/img/sponsors/newbyte.dark.png', href: 'https://newbyte.net.br' }, + { name: 'Optiwise', img: '/img/sponsors/optiwise.png', darkImg: '/img/sponsors/optiwise.dark.png', href: 'https://optiwise.nl' }, + { name: 'Postgres.AI', img: '/img/sponsors/postgresai.png', darkImg: '/img/sponsors/postgresai.dark.png', href: 'https://postgres.ai' }, { name: 'Staffery', img: '/img/sponsors/staffery.png', href: 'https://www.staffery.com' }, - { name: 'Toncarton', img: '/img/sponsors/toncarton.png', href: 'https://www.toncarton.com' }, - { name: 'We-Manage', img: '/img/sponsors/we-manage.png', href: 'https://we-manage.de' }, + { name: 'Toncarton', img: '/img/sponsors/toncarton.png', darkImg: '/img/sponsors/toncarton.dark.png', href: 'https://www.toncarton.com' }, + { name: 'We-Manage', img: '/img/sponsors/we-manage.png', darkImg: '/img/sponsors/we-manage.dark.png', href: 'https://we-manage.de' }, ]; +function normalizeLogoSize(event) { + const image = event.currentTarget; + if (!image.naturalWidth || !image.naturalHeight) { + return; + } + + if (image.naturalHeight / image.naturalWidth > 0.55) { + image.classList.add(styles.logoSquareAsset); + } +} + function LogoSet({ hidden = false }) { return (
@@ -31,10 +42,22 @@ function LogoSet({ hidden = false }) { {hidden + {sponsor.darkImg && ( + + )} ))}
diff --git a/src/components/TrustedByCarousel/styles.module.css b/src/components/TrustedByCarousel/styles.module.css index f2c82f5..6666793 100644 --- a/src/components/TrustedByCarousel/styles.module.css +++ b/src/components/TrustedByCarousel/styles.module.css @@ -77,6 +77,7 @@ height: 58px; padding: 12px 26px; flex-shrink: 0; + position: relative; } .logoImg { @@ -91,11 +92,35 @@ transition: filter 0.15s ease, opacity 0.15s ease; } +.logoSquareAsset { + width: 72px; + max-height: none; +} + .logoLink:hover .logoImg { filter: grayscale(40%) contrast(110%); opacity: 0.9; } +.logoDark { + display: none; +} + +:global(html[data-theme='dark']) .logoLight { + display: none; +} + +:global(html[data-theme='dark']) .logoDark { + display: block; + filter: grayscale(100%) brightness(0.88) contrast(105%); + opacity: 0.68; +} + +:global(html[data-theme='dark']) .logoLink:hover .logoDark { + filter: grayscale(40%) brightness(1) contrast(105%); + opacity: 0.9; +} + @keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } diff --git a/src/components/ValuePropsSection/styles.module.css b/src/components/ValuePropsSection/styles.module.css index 352d48a..4d3a281 100644 --- a/src/components/ValuePropsSection/styles.module.css +++ b/src/components/ValuePropsSection/styles.module.css @@ -26,7 +26,7 @@ border: 1px solid var(--color-border); border-radius: 2px; background: var(--color-bg); - box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.05); + box-shadow: 8px 8px 0 var(--shadow-pixel); transition: border-color 0.16s ease, box-shadow 0.16s ease, @@ -37,7 +37,7 @@ .card:hover { border-color: var(--color-primary); - box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.1); + box-shadow: 10px 10px 0 var(--shadow-pixel-hover); } /* ─── Icon ────────────────────────────────────────────────────────── */ diff --git a/src/css/custom.css b/src/css/custom.css index 00607fe..f9c7a8f 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -143,6 +143,10 @@ html.docs-wrapper[data-theme='light'] .theme-doc-toc-desktop { --color-text: #111111; --color-text-muted: #555555; --color-border: #e0e0e0; + --color-diagram-line: #8f8f8f; + --color-diagram-border: #b7b7b7; + --shadow-pixel: rgba(0, 0, 0, 0.05); + --shadow-pixel-hover: rgba(0, 0, 0, 0.1); --section-pt: 64px; --section-pb: 64px; @@ -152,6 +156,30 @@ html.docs-wrapper[data-theme='light'] .theme-doc-toc-desktop { font-family: var(--font-base); } +[data-theme='dark'] .landingPage { + --ifm-background-color: #11161d !important; + --ifm-background-surface-color: #11161d !important; + --ifm-font-color-base: #f9fafb; + --ifm-heading-color: #f9fafb; + --docusaurus-highlighted-code-line-bg: rgba(255, 255, 255, 0.08); + + --color-bg: #11161d; + --color-bg-alt: #11161d; + --color-surface: #11161d; + --color-text: #f9fafb; + --color-text-muted: #9ca3af; + --color-border: #252a31; + --color-black: #f9fafb; + --color-muted: #6b7280; + --color-diagram-line: #6f7782; + --color-diagram-border: #4b5563; + --shadow-pixel: rgba(255, 255, 255, 0.06); + --shadow-pixel-hover: rgba(255, 255, 255, 0.11); + + background-color: var(--color-bg); + color: var(--color-text); +} + .landingPage h1, .landingPage h2, .landingPage h3, @@ -171,6 +199,11 @@ html.docs-wrapper[data-theme='light'] .theme-doc-toc-desktop { background-color: var(--color-bg); } +[data-theme='dark'] body:has(.landingPage), +[data-theme='dark'] .landingPage main { + background-color: #11161d; +} + @media (max-width: 900px) { .landingPage { --section-pt: 48px; diff --git a/src/theme/Footer/index.js b/src/theme/Footer/index.js index b7dff0d..46cb604 100644 --- a/src/theme/Footer/index.js +++ b/src/theme/Footer/index.js @@ -1,6 +1,7 @@ import React from 'react'; import useBaseUrl from '@docusaurus/useBaseUrl'; import { useLocation } from '@docusaurus/router'; +import { useColorMode } from '@docusaurus/theme-common'; import OriginalFooter from '@theme-original/Footer'; import styles from './styles.module.css'; @@ -14,8 +15,14 @@ function normalizePath(pathname) { export default function Footer(props) { const { pathname } = useLocation(); + const { colorModeChoice, setColorMode } = useColorMode(); const homePath = useBaseUrl('/'); const isHomepage = normalizePath(pathname) === normalizePath(homePath); + const colorModeLabel = colorModeChoice ?? 'system'; + const isSystemColorMode = colorModeChoice == null; + const nextColorModeChoice = + isSystemColorMode ? 'light' : colorModeChoice === 'light' ? 'dark' : null; + const nextColorModeLabel = nextColorModeChoice ?? 'system'; if (!isHomepage) { return ; @@ -27,9 +34,21 @@ export default function Footer(props) {
-
- - Autobase +
+
+ + Autobase +
+ +

diff --git a/src/theme/Footer/styles.module.css b/src/theme/Footer/styles.module.css index deb0bc0..87940da 100644 --- a/src/theme/Footer/styles.module.css +++ b/src/theme/Footer/styles.module.css @@ -7,9 +7,20 @@ --color-text: #111111; --color-text-muted: #555555; --color-border: #e0e0e0; + --shadow-pixel: rgba(0, 0, 0, 0.05); + --shadow-pixel-hover: rgba(0, 0, 0, 0.1); background: var(--color-bg); } +:global(html[data-theme='dark']) .footer { + --color-bg: #11161d; + --color-text: #f9fafb; + --color-text-muted: #9ca3af; + --color-border: #252a31; + --shadow-pixel: rgba(255, 255, 255, 0.06); + --shadow-pixel-hover: rgba(255, 255, 255, 0.11); +} + .divider { width: 100%; height: 1px; @@ -27,11 +38,17 @@ } /* ─── Logo ────────────────────────────────────────────────────────── */ +.logoRow { + display: flex; + align-items: center; + justify-content: space-between; + gap: 20px; +} + .logoMark { display: flex; align-items: center; gap: 10px; - margin-bottom: 4px; } .logoText { @@ -42,6 +59,40 @@ line-height: 1; } +.themeToggle { + display: inline-flex; + align-items: center; + gap: 10px; + padding: 8px 12px; + border: 1px solid var(--color-border); + border-radius: 2px; + background: transparent; + color: var(--color-text-muted); + font-family: var(--font-base); + font-size: 14px; + font-weight: var(--fw-regular); + line-height: 1; + text-transform: uppercase; + cursor: pointer; + box-shadow: 4px 4px 0 var(--shadow-pixel, rgba(0, 0, 0, 0.05)); + transition: + border-color 0.16s ease, + box-shadow 0.16s ease, + color 0.16s ease, + transform 0.16s ease; +} + +.themeToggle:hover { + border-color: var(--color-primary); + color: var(--color-text); + transform: translate(2px, 2px); + box-shadow: 2px 2px 0 var(--shadow-pixel-hover, rgba(0, 0, 0, 0.1)); +} + +.themePrompt { + color: var(--color-primary); +} + /* ─── Copyright ───────────────────────────────────────────────────── */ .copyright { font-family: var(--font-base); @@ -69,6 +120,8 @@ @media (max-width: 600px) { .inner { padding: 32px 20px 40px; } + .logoRow { align-items: flex-start; } + .themeToggle { padding: 7px 10px; font-size: 12px; } } @media (max-width: 480px) { diff --git a/src/theme/Navbar/styles.module.css b/src/theme/Navbar/styles.module.css index 5215a86..76791e7 100644 --- a/src/theme/Navbar/styles.module.css +++ b/src/theme/Navbar/styles.module.css @@ -13,6 +13,7 @@ --color-bg: #F9FAFB; --color-surface: #f9f9f9; --color-text: #111111; + --color-text-muted: #858585; --color-border: #e0e0e0; --color-white: #ffffff; --color-primary: #ff5722; @@ -21,6 +22,14 @@ height: auto; } +:global(html[data-theme='dark']) .navbar { + --color-bg: #11161d; + --color-surface: #11161d; + --color-text: #f9fafb; + --color-text-muted: #9ca3af; + --color-border: #252a31; +} + /* ─── Inner container — matches hero padding ──────────────────────── */ .inner { display: flex; @@ -74,7 +83,7 @@ font-family: var(--font-base); font-size: 17px; font-weight: 400; - color: hsl(0, 0%, 52%); + color: var(--color-text-muted, hsl(0, 0%, 52%)); text-decoration: none; position: relative; white-space: nowrap; @@ -146,7 +155,7 @@ border: 1px solid var(--color-border); } -.ctaSecondary:hover { color: var(--color-text); border-color: #aaaaaa; } +.ctaSecondary:hover { color: var(--color-text); border-color: var(--color-text-muted, #aaaaaa); } /* ─── Icon links ──────────────────────────────────────────────────── */ .iconLink { @@ -164,6 +173,8 @@ .iconLink img { filter: brightness(0); } +:global(html[data-theme='dark']) .iconLink img { filter: brightness(0) invert(1); } + /* ─── Mobile ──────────────────────────────────────────────────────── */ .mobileActions { display: none; }