diff --git a/app/contribute/contribute-view.tsx b/app/contribute/contribute-view.tsx index 43351be6..23252f52 100644 --- a/app/contribute/contribute-view.tsx +++ b/app/contribute/contribute-view.tsx @@ -5,6 +5,7 @@ import { ContributeHero } from "@/components/contribute/contribute-hero"; import { ContributionCard } from "@/components/contribute/contribution-card"; import { ContributionEmptyState } from "@/components/contribute/contribution-empty-state"; import { ContributionHint } from "@/components/contribute/contribution-hint"; +import { CursorGlow } from "@/components/ui/cursor-glow"; const containerVariants = { hidden: { opacity: 0 }, @@ -39,24 +40,26 @@ export default function ContributeView({ cards }: { cards: ContributionCardData[
{cards.length > 0 ? ( - - {cards.map((card, index) => ( - - ))} - + + + {cards.map((card, index) => ( + + ))} + + ) : ( )} diff --git a/app/docs/view.tsx b/app/docs/view.tsx index 3e62284b..0e76fece 100644 --- a/app/docs/view.tsx +++ b/app/docs/view.tsx @@ -8,6 +8,7 @@ import { DocsBackground } from "@/components/docs/view/docs-background"; import { DocsCard } from "@/components/docs/view/docs-card"; import { DocsHeader } from "@/components/docs/view/docs-header"; import Cta from "@/components/shared/cta-section"; +import { CursorGlow } from "@/components/ui/cursor-glow"; import { DOC_PROJECTS } from "@/lib/docs-projects"; export function DocsView() { @@ -44,16 +45,18 @@ export function DocsView() {
- - {DOC_PROJECTS.map((project) => ( - - ))} - + + + {DOC_PROJECTS.map((project) => ( + + ))} + +
diff --git a/app/globals.css b/app/globals.css index e05a418e..8f8ce6e9 100644 --- a/app/globals.css +++ b/app/globals.css @@ -372,3 +372,1096 @@ pre[class*="language-"] { pre[class*="language-"] { color: var(--prism-text) !important; } + +/* EternalCode 2026 visual system */ +:root { + color-scheme: light; + --ec-bg: #f7f7f2; + --ec-panel: #fdfdf9; + --ec-panel-strong: #eeeee7; + --ec-footer: #efefe8; + --ec-text: #171914; + --ec-muted: rgb(23 25 20 / 0.66); + --ec-faint: rgb(23 25 20 / 0.46); + --ec-line: rgb(23 25 20 / 0.14); + --ec-soft: rgb(23 25 20 / 0.065); + --ec-accent: #3b82f6; + --ec-accent-text: #1d4ed8; + --ec-accent-ink: #ffffff; + --ec-nav: rgb(247 247 242 / 0.9); + --ec-code: #171a15; + --ec-code-text: #f3f5ec; + --ec-glow: rgb(59 130 246 / 0.18); + --ec-glow-core: rgb(59 130 246 / 0.34); +} + +.dark { + color-scheme: dark; + --ec-bg: #0d0f0d; + --ec-panel: #141713; + --ec-panel-strong: #090b09; + --ec-footer: #080a08; + --ec-text: #f1f3ea; + --ec-muted: rgb(241 243 234 / 0.62); + --ec-faint: rgb(241 243 234 / 0.42); + --ec-line: rgb(241 243 234 / 0.12); + --ec-soft: rgb(255 255 255 / 0.06); + --ec-accent: #60a5fa; + --ec-accent-text: #60a5fa; + --ec-accent-ink: #07111f; + --ec-nav: rgb(11 13 12 / 0.84); + --ec-code: #080a08; + --ec-code-text: #f4f5ef; + --ec-glow: rgb(96 165 250 / 0.17); + --ec-glow-core: rgb(96 165 250 / 0.32); +} + +html { + scroll-behavior: smooth; + background: var(--ec-bg); +} +body { + background: var(--ec-bg); + color: var(--ec-text); + font-family: var(--font-manrope), sans-serif; +} +::selection { + background: var(--ec-accent); + color: var(--ec-accent-ink); +} +.site-shell { + min-height: 100vh; + overflow: hidden; + background: var(--ec-bg); + color: var(--ec-text); +} +.site-nav { + border: 1px solid var(--ec-line); + border-radius: 1.1rem; + background: var(--ec-nav); + box-shadow: 0 18px 60px rgb(0 0 0 / 0.12); + backdrop-filter: blur(18px); +} +.nav-link { + border-radius: 999px; + padding: 0.55rem 0.9rem; + color: var(--ec-muted); + font-size: 0.82rem; + font-weight: 600; + transition: 0.2s ease; +} +.nav-link:hover, +.nav-link-active { + background: var(--ec-soft); + color: var(--ec-text); +} +.section-shell { + width: min(100% - 2rem, 92rem); + margin-inline: auto; +} +.hero-grid { + position: absolute; + inset: 0; + opacity: 0.48; + background-image: + linear-gradient(var(--ec-line) 1px, transparent 1px), + linear-gradient(90deg, var(--ec-line) 1px, transparent 1px); + background-size: 64px 64px; + mask-image: linear-gradient(to bottom, black 20%, transparent 90%); +} +.eyebrow, +.section-kicker { + display: flex; + align-items: center; + gap: 0.65rem; + font-family: var(--font-jetbrains-mono), monospace; + font-size: 0.68rem; + line-height: 1; + letter-spacing: 0.16em; + text-transform: uppercase; + color: var(--ec-muted); +} +.section-kicker span, +.hero-title span, +.text-link { + color: var(--ec-accent-text); +} +.status-dot { + display: inline-block; + width: 0.45rem; + height: 0.45rem; + flex: none; + border-radius: 50%; + background: var(--ec-accent); + box-shadow: 0 0 14px color-mix(in srgb, var(--ec-accent) 65%, transparent); +} +.hero-title { + max-width: 65rem; + margin-top: 1.7rem; + font-size: clamp(3.3rem, 8vw, 8.2rem); + font-weight: 600; + line-height: 0.88; + letter-spacing: -0.075em; +} +.primary-action, +.secondary-action, +.pill-link, +.text-link { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.6rem; + font-size: 0.82rem; + font-weight: 700; + transition: 0.2s ease; +} +.primary-action { + min-height: 3.2rem; + border-radius: 999px; + padding: 0 1.35rem; + background: var(--ec-accent); + color: var(--ec-accent-ink); +} +.primary-action:hover { + filter: brightness(1.04); + transform: translateY(-2px); +} +.secondary-action, +.pill-link { + min-height: 3.2rem; + border: 1px solid var(--ec-line); + border-radius: 999px; + padding: 0 1.25rem; + color: var(--ec-muted); +} +.secondary-action:hover, +.pill-link:hover { + border-color: color-mix(in srgb, var(--ec-text) 28%, transparent); + color: var(--ec-text); +} +.project-card, +.ec-card { + border-color: var(--ec-line); + background-color: var(--ec-panel); + color: var(--ec-text); +} +.project-card { + display: block; + min-height: 31rem; + border-width: 1px; + border-radius: 1.75rem; + padding: 1.5rem; + overflow: hidden; + transition: + transform 0.35s ease, + border-color 0.35s ease, + box-shadow 0.35s ease; +} +.project-card:hover { + transform: translateY(-6px); + border-color: color-mix(in srgb, var(--ec-text) 25%, transparent); + box-shadow: 0 22px 55px rgb(0 0 0 / 0.1); +} +.project-icon { + display: grid; + width: 3.25rem; + height: 3.25rem; + place-items: center; + border-radius: 1rem; + background: var(--ec-soft); + color: var(--ec-text); +} +.project-blue { + background-image: radial-gradient( + circle at 15% 20%, + color-mix(in srgb, var(--ec-accent) 20%, transparent), + transparent 38% + ); +} +.project-blue .project-icon { + color: var(--ec-accent-text); +} +.project-violet { + background-image: radial-gradient( + circle at 15% 20%, + rgb(37 99 235 / 0.16), + transparent 38% + ); +} +.project-violet .project-icon { + color: #2563eb; +} +.project-cyan { + background-image: radial-gradient( + circle at 15% 20%, + rgb(14 165 233 / 0.15), + transparent 38% + ); +} +.project-cyan .project-icon { + color: #0284c7; +} +.display-title { + max-width: 46rem; + font-size: clamp(2.55rem, 5vw, 5rem); + font-weight: 600; + line-height: 0.98; + letter-spacing: -0.06em; +} +.code-panel { + overflow: hidden; + border: 1px solid var(--ec-line); + border-radius: 1.25rem; + background: var(--ec-code); + color: var(--ec-code-text); + box-shadow: 0 30px 80px rgb(0 0 0 / 0.16); +} +.terminal-caret { + display: inline-block; + width: 0.5rem; + height: 1rem; + margin-left: 0.2rem; + vertical-align: middle; + background: var(--ec-accent); + animation: blink 1s steps(2) infinite; +} +@keyframes blink { + 50% { + opacity: 0; + } +} +.cta-panel { + display: flex; + flex-direction: column; + justify-content: space-between; + gap: 3rem; + border-radius: 2rem; + padding: clamp(2rem, 6vw, 5rem); + background: var(--ec-accent); + color: var(--ec-accent-ink); +} +.cta-button { + display: inline-flex; + width: fit-content; + align-items: center; + gap: 0.65rem; + border-radius: 999px; + padding: 1rem 1.25rem; + background: var(--ec-accent-ink); + color: white; + font-size: 0.85rem; + font-weight: 700; +} +.cursor-glow { + position: relative; +} +.cursor-glow [data-glow-card] { + --card-glow-x: 50%; + --card-glow-y: 50%; + --card-glow-opacity: 0; + isolation: isolate; + position: relative; + overflow: hidden; +} +.cursor-glow [data-glow-card]::before { + content: ""; + pointer-events: none; + position: absolute; + z-index: 0; + left: var(--card-glow-x); + top: var(--card-glow-y); + width: 19rem; + height: 19rem; + border-radius: 999px; + opacity: var(--card-glow-opacity); + background: radial-gradient( + circle, + var(--ec-glow-core), + var(--ec-glow) 42%, + transparent 72% + ); + filter: blur(24px); + transform: translate(-50%, -50%); + transition: opacity 0.22s ease; + will-change: left, top, opacity; +} +.cursor-glow [data-glow-card] > :not([class*="absolute"]) { + position: relative; + z-index: 1; +} + +main > div:not(.site-shell), +main > section { + background-color: var(--ec-bg) !important; + color: var(--ec-text); +} +.bg-gray-50, +.bg-light-gray-100 { + background-color: var(--ec-bg) !important; +} +.bg-white { + background-color: var(--ec-panel) !important; +} +.border-gray-200, +.border-white\/10 { + border-color: var(--ec-line) !important; +} +.text-gray-900, +.text-gray-800 { + color: var(--ec-text) !important; +} +.text-gray-600, +.text-gray-500 { + color: var(--ec-muted) !important; +} +.bg-blue-600 { + background-color: var(--ec-accent) !important; + color: var(--ec-accent-ink) !important; +} +.text-blue-600 { + color: var(--ec-accent-text) !important; +} +.rounded-xl, +.rounded-2xl { + border-radius: 1.1rem; +} +.prose { + --tw-prose-body: var(--ec-muted); + --tw-prose-headings: var(--ec-text); + --tw-prose-links: var(--ec-accent); + --tw-prose-bold: var(--ec-text); + --tw-prose-code: var(--ec-accent); +} + +@media (min-width: 768px) { + .cta-panel { + flex-direction: row; + align-items: end; + } +} +@media (max-width: 640px) { + .project-card { + min-height: 27rem; + } +} +@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) { + .cursor-glow-blob { + display: none; + } +} + +.code-panel [class*="text-white/"] { + color: rgb(255 255 255 / 0.48) !important; +} + +/* Minimal Minecraft hero */ +.hero-minimal { + position: relative; + display: grid; + min-height: 92svh; + place-items: center; + overflow: hidden; + border-bottom: 1px solid var(--ec-line); + padding: 9rem 1rem 5rem; +} +.hero-minimal::before { + content: ""; + position: absolute; + top: 20%; + left: 50%; + width: min(56rem, 90vw); + height: 24rem; + border-radius: 50%; + background: color-mix(in srgb, var(--ec-accent) 9%, transparent); + filter: blur(100px); + transform: translateX(-50%); +} +.hero-minimal-inner { + position: relative; + z-index: 2; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} +.hero-minimal-title { + max-width: 70rem; + margin-top: 1.7rem; + font-size: clamp(3.8rem, 9vw, 8.5rem); + font-weight: 600; + line-height: 0.88; + letter-spacing: -0.075em; +} +.hero-minimal-title span { + color: var(--ec-accent-text); +} +.hero-minimal-lead { + max-width: 43rem; + margin-top: 2rem; + color: var(--ec-muted); + font-size: clamp(1rem, 1.5vw, 1.18rem); + line-height: 1.75; +} +.hero-minimal-actions { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 0.75rem; + margin-top: 2rem; +} +.hero-minimal-scroll { + position: absolute; + z-index: 3; + bottom: 1.2rem; + left: 50%; + display: flex; + align-items: center; + gap: 0.45rem; + color: var(--ec-faint); + font-family: var(--font-jetbrains-mono), monospace; + font-size: 0.58rem; + letter-spacing: 0.08em; + text-transform: uppercase; + transform: translateX(-50%); + transition: color 0.2s ease; +} +.hero-minimal-scroll:hover { + color: var(--ec-text); +} +@media (max-width: 640px) { + .hero-minimal { + min-height: 88svh; + padding-top: 8rem; + } + .hero-minimal-title { + font-size: clamp(3.25rem, 16vw, 5.2rem); + } + .hero-minimal-scroll { + display: none; + } +} + +/* EternalCore product page */ +.ec-project-page { + overflow: hidden; + background: var(--ec-bg); + color: var(--ec-text); +} +.ec-project-hero { + position: relative; + min-height: 100svh; + overflow: hidden; + border-bottom: 1px solid var(--ec-line); + padding-top: 9rem; +} +.ec-project-hero::before { + content: ""; + position: absolute; + width: 46rem; + height: 46rem; + right: -14rem; + top: 5rem; + border-radius: 50%; + background: radial-gradient( + circle, + color-mix(in srgb, var(--ec-accent) 13%, transparent), + transparent 68% + ); +} +.ec-project-hero-layout { + position: relative; + z-index: 2; + display: grid; + min-height: calc(100svh - 12rem); + align-items: center; + gap: clamp(3rem, 7vw, 7rem); + padding-bottom: 5rem; +} +.ec-project-copy { + max-width: 48rem; +} +.ec-project-copy h1 { + max-width: 54rem; + margin-top: 1.6rem; + font-size: clamp(3.8rem, 7.5vw, 7.6rem); + font-weight: 600; + line-height: 0.9; + letter-spacing: -0.072em; +} +.ec-project-copy h1 span { + color: var(--ec-accent-text); +} +.ec-project-copy > p { + max-width: 42rem; + margin-top: 1.7rem; + color: var(--ec-muted); + font-size: clamp(1rem, 1.4vw, 1.18rem); + line-height: 1.75; +} +.ec-project-actions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + margin-top: 2rem; +} +.ec-project-note { + display: flex; + align-items: center; + gap: 0.55rem; + margin-top: 2rem; + color: var(--ec-faint); + font-family: var(--font-jetbrains-mono), monospace; + font-size: 0.62rem; +} +.ec-project-note svg { + color: var(--ec-accent-text); +} +.ec-project-visual { + width: 100%; + max-width: 44rem; + justify-self: end; +} +.ec-project-banner-frame { + position: relative; + aspect-ratio: 16 / 10; + overflow: hidden; + border: 1px solid var(--ec-line); + border-radius: 1.8rem; + background: var(--ec-panel); + box-shadow: 0 40px 100px rgb(3 10 24 / 0.18); +} +.ec-project-banner-overlay { + position: absolute; + inset: 0; + background: linear-gradient(145deg, transparent 52%, rgb(2 6 23 / 0.38)); +} +.ec-project-banner-chip { + position: absolute; + border: 1px solid rgb(255 255 255 / 0.18); + border-radius: 999px; + padding: 0.5rem 0.7rem; + background: rgb(5 10 20 / 0.62); + color: white; + font-family: var(--font-jetbrains-mono), monospace; + font-size: 0.58rem; + backdrop-filter: blur(12px); +} +.ec-chip-top { + top: 1rem; + right: 1rem; +} +.ec-chip-bottom { + right: 1rem; + bottom: 1rem; +} +.ec-project-scroll { + position: absolute; + z-index: 3; + bottom: 1.2rem; + left: 50%; + display: flex; + align-items: center; + gap: 0.45rem; + color: var(--ec-faint); + font-family: var(--font-jetbrains-mono), monospace; + font-size: 0.58rem; + text-transform: uppercase; + letter-spacing: 0.08em; + transform: translateX(-50%); +} +.ec-capabilities { + padding-block: 8rem; +} +.ec-section-intro { + max-width: 55rem; +} +.ec-section-intro h2 { + margin-top: 1.5rem; + font-size: clamp(2.8rem, 5.4vw, 5.7rem); + font-weight: 600; + line-height: 0.96; + letter-spacing: -0.06em; +} +.ec-section-intro > p { + max-width: 42rem; + margin-top: 1.5rem; + color: var(--ec-muted); + line-height: 1.75; +} +.ec-capability-grid { + display: grid; + gap: 1px; + margin-top: 4rem; + overflow: hidden; + border: 1px solid var(--ec-line); + border-radius: 1.6rem; + background: var(--ec-line); +} +.ec-capability { + display: flex; + min-height: 15rem; + flex-direction: column; + justify-content: space-between; + padding: 1.5rem; + background: var(--ec-panel); +} +.ec-capability svg { + color: var(--ec-accent-text); +} +.ec-capability strong { + margin-top: 3rem; + font-family: var(--font-jetbrains-mono), monospace; + font-size: clamp(2.5rem, 5vw, 4.5rem); + font-weight: 500; + letter-spacing: -0.07em; +} +.ec-capability span { + max-width: 12rem; + color: var(--ec-muted); + font-size: 0.72rem; + line-height: 1.5; +} +.ec-showcase-section { + border-block: 1px solid var(--ec-line); + padding-block: 8rem; + background: var(--ec-panel-strong); +} +.ec-section-intro-wide { + max-width: 67rem; +} +.ec-showcase-list { + display: flex; + flex-direction: column; + gap: 9rem; + margin-top: 7rem; +} +.ec-showcase-row { + display: grid; + align-items: center; + gap: clamp(2rem, 7vw, 7rem); +} +.ec-showcase-copy { + max-width: 29rem; +} +.ec-showcase-copy > span { + color: var(--ec-accent-text); + font-family: var(--font-jetbrains-mono), monospace; + font-size: 0.62rem; + text-transform: uppercase; + letter-spacing: 0.12em; +} +.ec-showcase-copy h3 { + margin-top: 1rem; + font-size: clamp(2.25rem, 4vw, 4.4rem); + font-weight: 600; + line-height: 1; + letter-spacing: -0.055em; +} +.ec-showcase-copy p { + margin-top: 1.3rem; + color: var(--ec-muted); + line-height: 1.75; +} +.ec-showcase-copy a { + display: inline-flex; + align-items: center; + gap: 0.5rem; + margin-top: 1.5rem; + color: var(--ec-accent-text); + font-size: 0.78rem; + font-weight: 700; +} +.ec-gif-frame { + position: relative; + aspect-ratio: 16 / 10; + overflow: hidden; + border: 1px solid var(--ec-line); + border-radius: 1.7rem; + background: #080b10; + box-shadow: 0 28px 70px rgb(3 10 24 / 0.16); +} +.ec-gif-frame::after { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.06); +} +.ec-gif-blue { + box-shadow: 0 28px 80px rgb(37 99 235 / 0.14); +} +.ec-gif-indigo { + box-shadow: 0 28px 80px rgb(79 70 229 / 0.14); +} +.ec-gif-sky { + box-shadow: 0 28px 80px rgb(14 165 233 / 0.14); +} +.ec-mini-gallery { + display: grid; + gap: 1rem; + margin-top: 9rem; +} +.ec-mini-card { + overflow: hidden; + border: 1px solid var(--ec-line); + border-radius: 1.25rem; + background: var(--ec-panel); +} +.ec-mini-image { + position: relative; + aspect-ratio: 16 / 10; + overflow: hidden; + background: #080b10; +} +.ec-mini-card > div:last-child { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.9rem 1rem; + color: var(--ec-muted); + font-size: 0.7rem; +} +.ec-mini-card svg { + color: var(--ec-accent-text); +} +.ec-config-section { + display: grid; + align-items: center; + gap: clamp(3rem, 8vw, 8rem); + padding-block: 10rem; +} +.ec-config-copy { + max-width: 34rem; +} +.ec-config-copy h2 { + margin-top: 1.4rem; + font-size: clamp(2.7rem, 5vw, 5.3rem); + font-weight: 600; + line-height: 0.97; + letter-spacing: -0.06em; +} +.ec-config-copy > p { + margin-top: 1.4rem; + color: var(--ec-muted); + line-height: 1.75; +} +.ec-config-copy ul { + display: grid; + gap: 0.8rem; + margin-top: 2rem; +} +.ec-config-copy li { + display: flex; + align-items: center; + gap: 0.65rem; + color: var(--ec-muted); + font-size: 0.78rem; +} +.ec-config-copy li svg { + color: var(--ec-accent-text); +} +.ec-config-preview { + min-width: 0; + overflow: hidden; + border: 1px solid var(--ec-line); + border-radius: 1.5rem; + background: var(--ec-code); + box-shadow: 0 35px 85px rgb(3 10 24 / 0.2); +} +.ec-config-window-bar { + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid rgb(255 255 255 / 0.1); + padding: 0.9rem 1rem; + color: rgb(255 255 255 / 0.45); + font-family: var(--font-jetbrains-mono), monospace; + font-size: 0.6rem; +} +.ec-config-code { + height: 36rem; + overflow: hidden; + padding: 1rem; + mask-image: linear-gradient(to bottom, black 76%, transparent); +} +.ec-config-code pre { + margin: 0 !important; + background: transparent !important; +} +.ec-project-cta { + display: flex; + align-items: end; + justify-content: space-between; + gap: 3rem; + margin-bottom: 8rem; + border-radius: 2rem; + padding: clamp(2rem, 6vw, 5rem); + background: linear-gradient(135deg, #2563eb, #4338ca); + color: white; +} +.ec-project-cta .section-kicker { + color: rgb(255 255 255 / 0.65); +} +.ec-project-cta .section-kicker span { + color: white; +} +.ec-project-cta h2 { + max-width: 52rem; + margin-top: 1.3rem; + font-size: clamp(2.7rem, 5vw, 5.5rem); + font-weight: 600; + line-height: 0.97; + letter-spacing: -0.06em; +} +.ec-project-cta-actions { + display: flex; + flex: none; + flex-direction: column; + gap: 0.7rem; +} +.ec-project-cta .primary-action { + background: white; + color: #111827; +} +.ec-project-cta .secondary-action { + border-color: rgb(255 255 255 / 0.25); + color: white; +} +@media (min-width: 768px) { + .ec-capability-grid { + grid-template-columns: repeat(4, 1fr); + } + .ec-mini-gallery { + grid-template-columns: repeat(3, 1fr); + } +} +@media (min-width: 1024px) { + .ec-project-hero-layout { + grid-template-columns: minmax(0, 1fr) minmax(31rem, 0.85fr); + } + .ec-showcase-row { + grid-template-columns: 0.7fr 1.3fr; + } + .ec-showcase-reverse { + grid-template-columns: 1.3fr 0.7fr; + } + .ec-showcase-reverse .ec-showcase-copy { + order: 2; + } + .ec-showcase-reverse .ec-gif-frame { + order: 1; + } + .ec-config-section { + grid-template-columns: 0.75fr 1.25fr; + } +} +@media (max-width: 1023px) { + .ec-project-hero { + padding-top: 8rem; + } + .ec-project-visual { + max-width: none; + justify-self: stretch; + } + .ec-config-preview { + transform: none !important; + } + .ec-project-cta { + align-items: flex-start; + flex-direction: column; + } + .ec-project-cta-actions { + flex-direction: row; + flex-wrap: wrap; + } +} +@media (max-width: 640px) { + .ec-project-copy h1 { + font-size: clamp(3.3rem, 15vw, 5rem); + } + .ec-capabilities, + .ec-showcase-section, + .ec-config-section { + padding-block: 6rem; + } + .ec-showcase-list { + gap: 6rem; + margin-top: 5rem; + } + .ec-mini-gallery { + margin-top: 6rem; + } + .ec-config-code { + height: 30rem; + } + .ec-project-scroll { + display: none; + } +} +@media (prefers-reduced-motion: reduce) { + .ec-project-copy, + .ec-project-visual, + .ec-config-preview { + transform: none !important; + } +} + +/* Clean community CTA */ +.cta-panel-clean { + position: relative; + overflow: visible; + align-items: end; + background: linear-gradient(135deg, #2563eb, #4338ca); + color: white; +} +.cta-wumpus-column { + display: flex; + width: 13rem; + flex: none; + flex-direction: column; + align-items: center; + gap: 0.75rem; + align-self: stretch; + justify-content: flex-end; +} +.cta-wumpus { + position: relative; + display: grid; + width: 13.25rem; + height: 15.25rem; + margin-top: -3rem; + place-items: end center; +} +.cta-wumpus-glow { + position: absolute; + right: 1.75rem; + bottom: 1rem; + left: 1.75rem; + height: 3.75rem; + border-radius: 50%; + background: rgb(96 165 250 / 0.62); + filter: blur(28px); + transition: + transform 0.35s ease, + opacity 0.35s ease; +} +.cta-wumpus-image { + position: relative; + z-index: 1; + width: auto; + height: 15.75rem; + object-fit: contain; + filter: drop-shadow(0 18px 22px rgb(15 23 42 / 0.22)); + transform: translateY(-0.9rem) rotate(-1deg); + transform-origin: 50% 80%; + transition: transform 0.35s cubic-bezier(0.2, 0.8, 0.2, 1); +} +.cta-wumpus:hover .cta-wumpus-image { + transform: translateY(-1.35rem) rotate(1.5deg) scale(1.025); +} +.cta-wumpus:hover .cta-wumpus-glow { + opacity: 0.9; + transform: scale(1.12); +} +.cta-button-clean { + width: 100%; + min-width: 12rem; + justify-content: center; + background: white; + color: #172554; + box-shadow: 0 14px 35px rgb(15 23 42 / 0.2); +} +.cta-button-clean:hover { + background: #eff6ff; + transform: translateY(-2px); +} + +/* EternalCore minimal pass */ +.ec-project-hero::before { + width: 38rem; + height: 38rem; + opacity: 0.65; +} +.ec-project-banner-frame { + border-radius: 1.25rem; + box-shadow: 0 24px 60px rgb(3 10 24 / 0.12); +} +.ec-project-banner-overlay, +.ec-project-banner-chip { + display: none; +} +.ec-capabilities { + padding-block: 7rem; +} +.ec-capability { + min-height: 12rem; +} +.ec-showcase-section { + padding-block: 7rem; + background: var(--ec-bg); +} +.ec-showcase-list { + gap: 7rem; + margin-top: 5rem; +} +.ec-showcase-row { + padding-block: 1rem; +} +.ec-gif-frame { + border-radius: 1.25rem; + box-shadow: none; +} +.ec-gif-blue, +.ec-gif-indigo, +.ec-gif-sky { + box-shadow: none; +} +.ec-mini-gallery { + display: none; +} +.ec-config-section { + padding-block: 8rem; +} +.ec-config-preview { + border-radius: 1.25rem; + box-shadow: 0 24px 60px rgb(3 10 24 / 0.14); +} +.ec-project-cta { + margin-bottom: 7rem; + border: 1px solid var(--ec-line); + background: var(--ec-panel); + color: var(--ec-text); +} +.ec-project-cta .section-kicker { + color: var(--ec-muted); +} +.ec-project-cta .section-kicker span { + color: var(--ec-accent-text); +} +.ec-project-cta .primary-action { + background: var(--ec-accent); + color: var(--ec-accent-ink); +} +.ec-project-cta .secondary-action { + border-color: var(--ec-line); + color: var(--ec-muted); +} +@media (max-width: 767px) { + .cta-panel-clean { + align-items: flex-start; + } + .cta-wumpus-column { + width: 100%; + } + .cta-wumpus { + width: 11.5rem; + height: 12.75rem; + margin-top: -1rem; + } + .cta-wumpus-image { + height: 13.25rem; + } + .cta-button-clean { + width: 100%; + } +} diff --git a/app/layout.tsx b/app/layout.tsx index 8054d389..eeaddaf3 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,5 +1,5 @@ import type { Metadata, Viewport } from "next"; -import { JetBrains_Mono, Poppins } from "next/font/google"; +import { JetBrains_Mono, Manrope } from "next/font/google"; import NextTopLoader from "nextjs-toploader"; import "./globals.css"; import "lenis/dist/lenis.css"; @@ -15,13 +15,12 @@ import { Providers } from "./providers"; export const dynamic = "force-static"; export const revalidate = 5; -const poppins = Poppins({ - weight: ["400", "500", "600", "700"], +const manrope = Manrope({ subsets: ["latin"], display: "swap", preload: true, fallback: ["system-ui", "arial"], - variable: "--font-poppins", + variable: "--font-manrope", }); const jetbrainsMono = JetBrains_Mono({ @@ -36,8 +35,8 @@ export const viewport: Viewport = { maximumScale: 5, userScalable: true, themeColor: [ - { media: "(prefers-color-scheme: light)", color: "#eff1f5" }, - { media: "(prefers-color-scheme: dark)", color: "#0d1117" }, + { media: "(prefers-color-scheme: light)", color: "#0b0d0c" }, + { media: "(prefers-color-scheme: dark)", color: "#0b0d0c" }, ], }; @@ -108,12 +107,12 @@ export default function RootLayout({ }>) { return ( @@ -124,7 +123,7 @@ export default function RootLayout({ easing="ease" height={3} initialPosition={0.08} - shadow="0 0 10px #3b82f6,0 0 5px #3b82f6" + shadow="0 0 10px #3b82f6" showSpinner={false} speed={200} /> @@ -132,7 +131,7 @@ export default function RootLayout({ -
+
{children}
diff --git a/app/notification-generator/page.tsx b/app/notification-generator/page.tsx index d1245b4b..37422c6f 100644 --- a/app/notification-generator/page.tsx +++ b/app/notification-generator/page.tsx @@ -62,7 +62,7 @@ export default function NotificationGeneratorPage() {
-

+

Notification Generator

diff --git a/app/projects/eternalcombat/page.tsx b/app/projects/eternalcombat/page.tsx index 365a298e..3b39e63c 100644 --- a/app/projects/eternalcombat/page.tsx +++ b/app/projects/eternalcombat/page.tsx @@ -20,12 +20,12 @@ export default function EternalCombatPage() { const scale = useTransform(scrollYProgress, [0, 0.5], [1, 0.95]); return ( -
+
{/* Background Decor */}
-
+
@@ -42,9 +42,9 @@ export default function EternalCombatPage() { PvP Evolved
-

+

Combat Logging,
- + Solved Forever.

@@ -103,7 +103,7 @@ export default function EternalCombatPage() {
-
+
-
-
+
+
latest.txt
@@ -145,7 +145,7 @@ export default function EternalCombatPage() {
[19:23:01]{" "} - + ⚠ You are in combat! {" "} @@ -153,7 +153,7 @@ export default function EternalCombatPage() {
...
-
+
[19:23:45] vLucky tried to disconnect.
diff --git a/app/projects/eternalcore/page.tsx b/app/projects/eternalcore/page.tsx index ec290222..8f95c8b7 100644 --- a/app/projects/eternalcore/page.tsx +++ b/app/projects/eternalcore/page.tsx @@ -1,317 +1,239 @@ "use client"; -import { m, motion, useScroll, useTransform } from "framer-motion"; -import { Book, Check, ChevronRight, Download, Layers, Settings, Zap } from "lucide-react"; +import { motion, useScroll, useTransform } from "framer-motion"; +import { + ArrowDownRight, + ArrowRight, + BookOpen, + Box, + Check, + Download, + Github, + Layers3, + MessagesSquare, + Settings2, + ShieldCheck, + Zap, +} from "lucide-react"; import Image from "next/image"; +import Link from "next/link"; import { useRef } from "react"; -import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; -import { FacadePattern } from "@/components/ui/facade-pattern"; -import { FadeIn, MotionSection, ScaleIn, SlideIn } from "@/components/ui/motion/motion-components"; -import { slideUp } from "@/lib/animations/variants"; -import netlifyImageLoader from "@/lib/netlify-image-loader"; - import { ConfigPreview } from "./config-preview"; -import { EternalShowcase } from "./eternal-showcase"; + +const capabilities = [ + { icon: Box, value: "80+", label: "commands without legacy baggage" }, + { icon: Zap, value: "Paper", label: "built for the modern server stack" }, + { icon: Layers3, value: "Folia", label: "region-aware from the beginning" }, + { icon: ShieldCheck, value: "OSS", label: "inspect it, change it, ship it" }, +]; + +const showcases = [ + { + eyebrow: "Homes", + title: "Teleportation that feels predictable.", + description: + "Named homes, permission-based limits and clear feedback for players. Useful defaults first; configuration when you need it.", + image: "/docs/eternalcore/homes/sethome.gif", + accent: "blue", + }, + { + eyebrow: "Communication", + title: "Messages people can actually read.", + description: + "Private messages, broadcasts and admin channels with modern formatting—without assembling a small novel of nested builders.", + image: "/docs/eternalcore/adminchat-channel.gif", + accent: "sky", + }, +]; export default function EternalCorePage() { - const targetRef = useRef(null); - const { scrollYProgress } = useScroll({ - target: targetRef, + const heroRef = useRef(null); + const configRef = useRef(null); + const { scrollYProgress: heroProgress } = useScroll({ + target: heroRef, offset: ["start start", "end start"], }); - - const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0]); - const scale = useTransform(scrollYProgress, [0, 0.5], [1, 0.95]); + const { scrollYProgress: configProgress } = useScroll({ + target: configRef, + offset: ["start end", "end start"], + }); + const heroY = useTransform(heroProgress, [0, 1], [0, 120]); + const heroScale = useTransform(heroProgress, [0, 0.8], [1, 0.94]); + const configY = useTransform(configProgress, [0, 1], [70, -70]); return ( -
- {/* Background Decor */} -
-
-
-
- -
- -
- {/* Hero Section */} -
- - {/* Text Content */} -
- - -
- - Next-Gen Essentials -
-
- - -

- Essential commands. -
- - Uncompromised performance. - -

-
- - -

- EternalCore is a modern, open-source replacement for EssentialsX. Built for - Paper & Folia to deliver maximum performance without the legacy bloat. -

-
- - - - - - -
+
+
+
+
+ +
EternalCore · Open source Minecraft plugin
+

+ Everything your server needs. + Nothing it does not. +

+

+ A modern essentials plugin for Paper and Folia. Commands, homes, moderation, chat and + everyday server tools—designed as one coherent experience. +

+
+ + Download EternalCore + + + Read documentation +
- - {/* Project Banner Placeholder */} -
- -
- EternalCore Project Banner -
-
- +
+ Free, open source and not followed by an enterprise + pricing call.
-
- {/* Features Section */} -
-
- -

- The core of your network. -

-

- Everything you need to run a professional server, available for free. -

-
+ +
+ EternalCore project banner +
+
+ +
+ + See it in action + +
+ +
+
+
+ 01 One plugin, one consistent system +
+

Essentials rebuilt for how servers run today.

+

+ EternalCore replaces a patchwork of utilities with a focused foundation that is easier + to operate, easier to configure and easier to extend. +

+
+
+ {capabilities.map((item) => { + const Icon = item.icon; + return ( +
+ + {item.value} + {item.label} +
+ ); + })} +
+
+ +
+
+
+
+ 02 Real features, not mockups +
+

Watch the plugin work.

+

Two everyday workflows, shown exactly as players and administrators use them.

- - {[ - { - title: "80+ Commands", - description: - "From essential administration to fun mechanics, we have covered every use case you can imagine.", - icon: Layers, - iconColor: "text-purple-500", - gradient: "from-purple-500/20 to-indigo-500/20", - }, - { - title: "Open Source & Free", - description: - "EternalCore is and will always be free. Inspect the code, contribute, and build with confidence.", - icon: Download, - iconColor: "text-green-500", - gradient: "from-green-500/20 to-emerald-500/20", - }, - { - title: "Paper & Folia", - description: - "Built specifically for modern server software. 100% async and optimized for high-performance.", - icon: Zap, - iconColor: "text-yellow-500", - gradient: "from-yellow-500/20 to-orange-500/20", - }, - { - title: "Rich Formatting", - description: - "Full support for modern MiniMessage and legacy &c&lcolor codes simultaneously.", - icon: Check, - iconColor: "text-blue-500", - gradient: "from-blue-500/20 to-cyan-500/20", - }, - ].map((feature) => ( - - -
+ {showcases.map((showcase, index) => ( +
+
+ {showcase.eyebrow} +

{showcase.title}

+

{showcase.description}

+ + Explore this feature + +
+ + {`${showcase.eyebrow} - -
- -
-

- {feature.title} -

-

- {feature.description} -

- - +
+
))} - -
-
- - - -
- {/* Configuration Section */} -
-
- -
- - Configuration -
-

- Configuration
- Done Right. -

-

- Forget about guessing property names. EternalCore uses a strongly-typed - configuration system that ensures your settings are always valid and automatically - up-to-date. -

-
    - {[ - "Automatic config updates", - "Detailed comments generated automatically", - "Reload-safe architecture", - ].map((item) => ( -
  • -
    - -
    - {item} -
  • - ))} -
-
- - -
- {/* The "Long Screenshot" Container */} -
- {/* Window Controls */} -
-
-
-
-
-
-
- eternalcore - - config.yml -
-
- - {/* Tilted Content */} - {/* Content Container (Standard, non-tilted) */} -
- {/* Inner blur container */} -
- {/* Auto-scrolling animation container */} -
- - {/* Duplicate content for seamless loop */} - -
-
-
- - {/* Gradient overlay to fade bottom */} -
+
+
+
- {/* Animation Styles */} - -
-
- +
+
+
+ 03 Configuration without archaeology
-
+

Detailed when you need it. Sensible before you touch it.

+

+ Start with useful defaults, then tune homes, chat, databases, cooldowns and server + behavior from one readable configuration. +

+
    +
  • + Human-readable YAML +
  • +
  • + English and Polish messages +
  • +
  • + SQLite, MySQL, MariaDB and PostgreSQL +
  • +
+
+ +
+ config.yml + EternalCore / main +
+
+ +
+
+ - {/* Footer CTA */} -
- -

- Ready to upgrade your server? -

-

- Join hundreds of servers already using EternalCore for a more stable and efficient - experience. -

-
- - -
-
-
-
+
+
+
+ 04 Ready when your server is +
+

Replace the essentials pile with one modern core.

+
+
+ + Download latest build + + + View source + +
+
); } diff --git a/components/builds/build-header.tsx b/components/builds/build-header.tsx index b9668752..1fd40371 100644 --- a/components/builds/build-header.tsx +++ b/components/builds/build-header.tsx @@ -4,12 +4,18 @@ export function BuildHeader() { return (
-

+
+ Releases Distribution center +
+

Build Explorer

Access stable releases and development builds for all our projects.

+

+ Stable means tested. Dev means you enjoy surprises. +

); diff --git a/components/builds/build-row.tsx b/components/builds/build-row.tsx index e4102435..045e3412 100644 --- a/components/builds/build-row.tsx +++ b/components/builds/build-row.tsx @@ -26,8 +26,8 @@ function BuildStatusBadge({ type }: { type: "STABLE" | "DEV" }) {
{type === "STABLE" ? : } diff --git a/components/contribute/contribute-hero.tsx b/components/contribute/contribute-hero.tsx index b52ed2dc..7f26b793 100644 --- a/components/contribute/contribute-hero.tsx +++ b/components/contribute/contribute-hero.tsx @@ -4,17 +4,15 @@ import { MotionSection, SlideIn } from "@/components/ui/motion/motion-components export function ContributeHero() { return ( -
+
-

- Become an Open Source{" "} - - - Volunteer - - {" "} +
+ Contribute Build in public +
+

+ Make open source better with us.

diff --git a/components/contribute/contribution-card.tsx b/components/contribute/contribution-card.tsx index ca1d4198..5f4cb017 100644 --- a/components/contribute/contribution-card.tsx +++ b/components/contribute/contribution-card.tsx @@ -38,7 +38,7 @@ export function ContributionCard({ return ( - +
diff --git a/components/docs/eternalcore/placeholder/placeholder-table.tsx b/components/docs/eternalcore/placeholder/placeholder-table.tsx index 1ae385af..ab71a5b5 100644 --- a/components/docs/eternalcore/placeholder/placeholder-table.tsx +++ b/components/docs/eternalcore/placeholder/placeholder-table.tsx @@ -57,7 +57,7 @@ export function PlaceholderTable({ placeholders }: PlaceholderTableProps) { className={cn( "rounded px-2 py-0.5 font-medium text-xs", p.requiresPlayer - ? "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300" + ? "bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300" : "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400" )} > diff --git a/components/docs/search/search-modal.tsx b/components/docs/search/search-modal.tsx index c0958049..07a1ece9 100644 --- a/components/docs/search/search-modal.tsx +++ b/components/docs/search/search-modal.tsx @@ -45,7 +45,7 @@ const CATEGORY_BADGE_STYLES: Record = { Multification: "bg-blue-100 text-blue-700 ring-blue-200 dark:bg-blue-500/20 dark:text-blue-200 dark:ring-blue-500/40", Contribute: - "bg-emerald-100 text-emerald-700 ring-emerald-200 dark:bg-emerald-500/20 dark:text-emerald-200 dark:ring-emerald-500/40", + "bg-sky-100 text-sky-700 ring-sky-200 dark:bg-sky-500/20 dark:text-sky-200 dark:ring-sky-500/40", }; const DOCS_PREFIX_REGEX = /^\/docs\//; diff --git a/components/docs/sidebar/doc-sidebar.tsx b/components/docs/sidebar/doc-sidebar.tsx index 8bc3c609..71bdae48 100644 --- a/components/docs/sidebar/doc-sidebar.tsx +++ b/components/docs/sidebar/doc-sidebar.tsx @@ -75,7 +75,7 @@ const DocSidebar: FC = ({ className = "", onItemClick, sidebarS rotate: prefersReducedMotion ? 0 : 5, }} > - +

Documentation

diff --git a/components/docs/view/docs-card.tsx b/components/docs/view/docs-card.tsx index ad237b75..cc3a4c2c 100644 --- a/components/docs/view/docs-card.tsx +++ b/components/docs/view/docs-card.tsx @@ -17,7 +17,7 @@ export function DocsCard({ project }: DocsCardProps) { return ( - +
diff --git a/components/docs/view/docs-header.tsx b/components/docs/view/docs-header.tsx index 472e3e95..1f0381b7 100644 --- a/components/docs/view/docs-header.tsx +++ b/components/docs/view/docs-header.tsx @@ -4,16 +4,22 @@ export function DocsHeader() { const { title, description } = DOCS_PAGE_CONFIG; return ( -
+
-

+
+ Library Product documentation +
+

{title}

{description}

+

+ Written by humans. Tested by humans. Typos also provided by humans. +

diff --git a/components/footer/footer.tsx b/components/footer/footer.tsx index a2a19c95..0e8b8f01 100644 --- a/components/footer/footer.tsx +++ b/components/footer/footer.tsx @@ -1,214 +1,74 @@ -"use client"; - -import { Icon } from "@iconify/react"; -import { motion } from "framer-motion"; +import { ArrowUpRight } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; - -import DiscordIcon from "@/components/icons/discord"; -import GitHubIcon from "@/components/icons/github"; -import TikTokIcon from "@/components/icons/round-tiktok"; -import YouTubeIcon from "@/components/icons/youtube"; import logo from "@/public/logo.svg"; -interface FooterLink { - href: string; - label: string; - isExternal?: boolean; -} - -interface FooterSection { - title: string; - links: FooterLink[]; -} - -const footerSections: FooterSection[] = [ +const groups = [ { - title: "Product", + title: "Explore", links: [ - { href: "/builds", label: "Build Explorer" }, - { href: "https://docs.eternalcode.pl/", label: "Documentation", isExternal: true }, - { href: "https://repo.eternalcode.pl/#/", label: "Repository", isExternal: true }, - { href: "https://status.eternalcode.pl/", label: "Status", isExternal: true }, + ["Documentation", "/docs"], + ["Team", "/team"], + ["Contribute", "/contribute"], + ["Builds", "/builds"], ], }, { title: "Projects", links: [ - { href: "/projects/eternalcore", label: "EternalCore" }, - { href: "/projects/eternalcombat", label: "EternalCombat" }, - ], - }, - { - title: "Community", - links: [ - { href: "https://discord.com/invite/FQ7jmGBd6c", label: "Discord", isExternal: true }, - { href: "https://github.com/EternalCodeTeam", label: "GitHub", isExternal: true }, - { - href: "https://www.youtube.com/channel/UC2BEaMJWxxUscN50AD0oY_Q", - label: "YouTube", - isExternal: true, - }, - { href: "https://www.tiktok.com/@eternalcode.pl", label: "TikTok", isExternal: true }, + ["EternalCore", "/projects/eternalcore"], + ["EternalCombat", "/projects/eternalcombat"], + ["Multification", "/docs/multification"], ], }, - { - title: "Resource", - links: [ - { - href: "https://spigotmc.org/resources/authors/eternalcodeteam.1570200/", - label: "SpigotMC", - isExternal: true, - }, - { - href: "https://modrinth.com/organization/eternalcodeteam", - label: "Modrinth", - isExternal: true, - }, - { href: "https://bstats.org/author/vLucky", label: "bStats", isExternal: true }, - ], - }, - { - title: "Company", - links: [ - { href: "/#about", label: "About" }, - { href: "/team", label: "Team" }, - { href: "/contribute", label: "Contribute" }, - ], - }, -]; - -const socialLinks = [ - { - href: "https://github.com/EternalCodeTeam", - label: "GitHub", - icon: , - }, - { - href: "https://discord.com/invite/FQ7jmGBd6c", - label: "Discord", - icon: , - }, - { - href: "https://www.youtube.com/channel/UC2BEaMJWxxUscN50AD0oY_Q", - label: "YouTube", - icon: , - }, - { - href: "https://www.tiktok.com/@eternalcode.pl", - label: "TikTok", - icon: , - }, ]; export default function Footer() { - const currentYear = new Date().getFullYear(); - return ( -
-
-
-
- - EternalCode Logo - - EternalCode - - -

- Building high-quality, open-source Minecraft solutions. Empowering communities with - reliable software since 2021. -

-
- {socialLinks.map((item) => ( - +
+
+ + + + + EternalCode. + +

+ Open-source infrastructure for ambitious Minecraft communities, designed and maintained + in Poland. +

+ + Follow development + +
+ {groups.map((group) => ( +
+

+ {group.title} +

+
+ {group.links.map(([label, href]) => ( + - {item.icon} - + {label} + ))}
- -
- {footerSections.map((section) => ( -
-

- {section.title} -

-
    - {section.links.map((link) => ( -
  • - {link.isExternal ? ( - - {link.label} - - ) : ( - - {link.label} - - )} -
  • - ))} -
-
- ))} -
-
- -
-
-

- © {currentYear} EternalCodeTeam. All rights reserved. -

-
- - - - - - - - Powered by Netlify - - - - Designed with by the EternalCodeTeam. - -
-
-
+ ))} +
+
+ © {new Date().getFullYear()} EternalCodeTeam + Open source. Built with care. Occasionally fixed after midnight.
); diff --git a/components/hero/hero.tsx b/components/hero/hero.tsx index d5ea9902..1d046a35 100644 --- a/components/hero/hero.tsx +++ b/components/hero/hero.tsx @@ -1,106 +1,66 @@ "use client"; -import { m } from "framer-motion"; -import { Github } from "lucide-react"; -import ArrowForwardHeroIcon from "@/components/icons/arrow-forward-hero"; -import { Button } from "@/components/ui/button"; -import { FadeIn, MotionSection, SlideIn } from "@/components/ui/motion/motion-components"; -import Terminal from "./terminal/terminal-window"; +import { motion } from "framer-motion"; +import { ArrowDownRight, ArrowRight, Github } from "lucide-react"; +import Link from "next/link"; export default function Hero() { return ( -
- {/* Background Blob - using CSS animation for better performance */} -
+
+
+
+ + Open source, built by friends + - - {/* Text Content */} -
- {/* Title */} - -

- - EternalCode.pl - -

-
+ + Minecraft plugins +
+ made for real servers. +
- {/* Subtitle */} - -

- Building the future with{" "} - - - open source - - - - . Join a community of passionate developers crafting the next generation of software - tools. -

-
+ + We are a group of friends building open-source tools we enjoy using ourselves. Useful + defaults, readable docs and no corporate nonsense. + - {/* Buttons */} - + + Explore plugins + + - + GitHub + + +
- - -
- - {/* Terminal - Right Side */} - -
- -
-
- -
+ + More about us + +
); } diff --git a/components/hero/navbar.tsx b/components/hero/navbar.tsx index 63fa258e..c0cdc1ca 100644 --- a/components/hero/navbar.tsx +++ b/components/hero/navbar.tsx @@ -1,446 +1,96 @@ "use client"; import { AnimatePresence, motion } from "framer-motion"; -import { ChevronDown, ExternalLink, Menu, Wrench, X } from "lucide-react"; +import { ArrowUpRight, Menu, X } from "lucide-react"; import Image from "next/image"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { useCallback, useEffect, useRef, useState } from "react"; -import { createPortal } from "react-dom"; - -import AnnouncementBanner from "@/components/hero/announcement-banner"; -import { slideDown } from "@/lib/animations/variants"; -import { cn } from "@/lib/utils"; +import { useState } from "react"; import logo from "@/public/logo.svg"; import ThemeSwitchButton from "./theme-switch-button"; -import { TOOLS_OPTIONS } from "./tools-dropdown"; - -interface NavLink { - href: string; - label: string; - isExternal?: boolean; -} -const NAV_LINKS: NavLink[] = [ +const links = [ { href: "/", label: "Home" }, - { href: "/team", label: "Team" }, { href: "/docs", label: "Docs" }, + { href: "/team", label: "Team" }, { href: "/contribute", label: "Contribute" }, + { href: "/builds", label: "Builds" }, ]; -const EXTERNAL_LINKS: NavLink[] = [ - { - href: "https://repo.eternalcode.pl/#/", - label: "Repository", - isExternal: true, - }, - { - href: "https://status.eternalcode.pl/", - label: "Status", - isExternal: true, - }, -]; - -const TOOLS_LINKS = TOOLS_OPTIONS.map((opt) => ({ - label: opt.label, - href: opt.value, -})); +export default function Navbar() { + const pathname = usePathname(); + const [open, setOpen] = useState(false); -function NavItem({ href, label, isActive, isExternal }: NavLink & { isActive: boolean }) { return ( - - - {label} - {!!isExternal && } - - {!!isActive && ( - - )} - - ); -} - -function ToolsMenu() { - const [isOpen, setIsOpen] = useState(false); - const menuRef = useRef(null); - - useEffect(() => { - const handleClick = (e: MouseEvent) => { - if (menuRef.current && !menuRef.current.contains(e.target as Node)) { - setIsOpen(false); - } - }; - if (isOpen) { - document.addEventListener("mousedown", handleClick); - } - return () => document.removeEventListener("mousedown", handleClick); - }, [isOpen]); + ); } diff --git a/components/home/animated-home.tsx b/components/home/animated-home.tsx index 634771fa..3370738f 100644 --- a/components/home/animated-home.tsx +++ b/components/home/animated-home.tsx @@ -1,77 +1,237 @@ "use client"; -import { m } from "framer-motion"; -import dynamic from "next/dynamic"; +import { motion } from "framer-motion"; +import { + ArrowRight, + Blocks, + BookOpen, + Box, + Check, + Code2, + Github, + PackageCheck, + Sparkles, + Users, +} from "lucide-react"; +import Link from "next/link"; import Hero from "@/components/hero/hero"; -import { FacadePattern } from "@/components/ui/facade-pattern"; -import VisibleSection from "@/components/ui/visible-section"; +import Cta from "@/components/shared/cta-section"; +import { CursorGlow } from "@/components/ui/cursor-glow"; -const About = dynamic(() => import("@/components/home/about/about-section"), { - loading: () =>
, -}); -const Cta = dynamic(() => import("@/components/shared/cta-section"), { - loading: () =>
, -}); -const Faq = dynamic(() => import("@/components/home/faq/faq-section"), { - loading: () =>
, -}); -const Features = dynamic(() => import("@/components/home/features/features"), { - loading: () =>
, -}); -const Sponsors = dynamic(() => import("@/components/home/sponsors/sponsors-section"), { - loading: () =>
, -}); +const projects = [ + { + name: "EternalCore", + description: "A complete, production-ready foundation for modern Minecraft servers.", + href: "/projects/eternalcore", + tag: "Server toolkit", + icon: Box, + tone: "blue", + }, + { + name: "EternalCombat", + description: "Precise combat control designed for competitive communities.", + href: "/projects/eternalcombat", + tag: "Combat engine", + icon: Sparkles, + tone: "violet", + }, + { + name: "Multification", + description: "A flexible text format that makes rich messages effortless.", + href: "/docs/multification", + tag: "Developer library", + icon: Code2, + tone: "cyan", + }, +]; + +const principles = [ + { + icon: PackageCheck, + title: "Production first", + text: "Tools shaped by real servers, strict reviews and measurable performance.", + }, + { + icon: BookOpen, + title: "Documented deeply", + text: "Clear guides, practical examples and APIs that respect your time.", + }, + { + icon: Users, + title: "Built in public", + text: "Open roadmaps, transparent decisions and a community that can contribute.", + }, + { + icon: Blocks, + title: "Designed to compose", + text: "Focused projects that work brilliantly alone and even better together.", + }, +]; export default function AnimatedHome() { return ( - -
-
- -
+
+ -
+
+
+ 01 Selected projects +
+

+ Things we built because apparently playing Minecraft was not enough. +

+ + {projects.map((project, index) => { + const Icon = project.icon; + return ( + + +
+ + + + + 0{index + 1} / 03 + +
+
+ + {project.tag} + +

+ {project.name} +

+

+ {project.description} +

+
+
+ Explore project{" "} + +
+ +
+ ); + })} +
+
-
+
+
+
+
+ 02 Our standard +
+

Software people trust at 3 AM.

+

+ We are an open-source engineering team from Poland. We build dependable tools for + server owners and developers who care about quality, clarity and control. +

+ + Meet the team + +
+ + {principles.map((item) => { + const Icon = item.icon; + return ( +
+ +

+ {item.title} +

+

{item.text}

+
+ ); + })} +
+
+
-
+
+
+ {[ + ["10+", "open-source projects"], + ["100k+", "monthly downloads"], + ["24/7", "community-driven development"], + ].map(([value, label]) => ( +
+ + {value} + + {label} +
+ ))} +
+
- -
+
+
+
+
+ + eternalcode / main +
+
+

+ $ ./gradlew build +

+

Resolving production modules...

+

Running quality gates...

+

+ + Build successful in 2.4s +

+

+ $ deploy --with-confidence{" "} + +

+
+
+
+
+ 03 Developer experience +
+

Complex under the hood. Calm on the surface.

+

+ Predictable configuration, useful defaults and documentation written for shipping—not + guessing. +

+
+ + Read docs + + + View source + +
+
+
+
-
- - - - - - -
- + +
); } diff --git a/components/home/features/features.tsx b/components/home/features/features.tsx index c1ae8b0c..fbf6decb 100644 --- a/components/home/features/features.tsx +++ b/components/home/features/features.tsx @@ -7,6 +7,7 @@ import JavaIcon from "@/components/icons/java"; import TabNew from "@/components/icons/tab-new"; import SectionTitle from "@/components/section-title"; import { Card } from "@/components/ui/card"; +import { CursorGlow } from "@/components/ui/cursor-glow"; import { MotionSection, SlideIn } from "@/components/ui/motion/motion-components"; import { slideUp } from "@/lib/animations/variants"; @@ -24,14 +25,14 @@ const features: Feature[] = [ title: "Java Ecosystem", description: "We harness the full power of the Java ecosystem to build scalable, high-performance server-side applications and plugins that you can rely on.", - color: "from-orange-500/20 to-red-500/20", + color: "from-blue-500/20 to-indigo-500/20", }, { icon:
); diff --git a/components/notification-generator/tabs/sound/sound-table.tsx b/components/notification-generator/tabs/sound/sound-table.tsx index c7a4c1a4..4ba49756 100644 --- a/components/notification-generator/tabs/sound/sound-table.tsx +++ b/components/notification-generator/tabs/sound/sound-table.tsx @@ -267,7 +267,7 @@ function SoundRow({ className={`border-gray-100 border-b hover:bg-gray-50 dark:border-gray-700 dark:hover:bg-gray-800 ${ selectedSound?.id === sound.id ? "bg-blue-50 dark:bg-blue-900/20" : "" } ${ - currentlyPlayingId === sound.id ? "bg-green-50 dark:bg-green-900/20" : "" + currentlyPlayingId === sound.id ? "bg-blue-50 dark:bg-blue-900/20" : "" } cursor-pointer transition-colors duration-150`} onClick={() => onSelectSound(sound.id)} > diff --git a/components/shared/cta-section.tsx b/components/shared/cta-section.tsx index c75850ce..9a80a933 100644 --- a/components/shared/cta-section.tsx +++ b/components/shared/cta-section.tsx @@ -1,39 +1,56 @@ "use client"; import { Icon } from "@iconify/react"; - -import { Button } from "@/components/ui/button"; -import { SlideIn } from "@/components/ui/motion/motion-components"; +import { ArrowUpRight, MessageCircle, Users } from "lucide-react"; +import Image from "next/image"; export default function Cta() { return ( -
-
- -
-

- Join our Community -

-

- Connect with other developers, showcase your projects, and get help with EternalCode - libraries. The best discussions happen on our Discord. -

-
- -
+
+
+
+ + Build with us + +

+ Good software gets better in good company. +

+

+ Ask questions, share feedback or just hang out with people who also spend too much time + thinking about Minecraft server plugins. +

+
+ + Developers & server owners + + + Help, feedback & releases + +
+
+ +
); diff --git a/components/team/team-hero.tsx b/components/team/team-hero.tsx index cccf57c0..d825af5c 100644 --- a/components/team/team-hero.tsx +++ b/components/team/team-hero.tsx @@ -4,22 +4,23 @@ import { MotionSection, SlideIn } from "@/components/ui/motion/motion-components export default function TeamHero() { return ( -
+
-

- The Architects of{" "} - - Innovation - +
+ People EternalCode team +
+

+ Friends who happen to build{" "} + dependable software.

- Meet the developers, designers, and creators who build powerful open-source tools. - Driven by curiosity and united by code. + No office, no matching hoodies, no quarterly targets. Just people who enjoy making + useful open-source things together.

diff --git a/components/team/team-member.tsx b/components/team/team-member.tsx index ab9171e5..5742f8ad 100644 --- a/components/team/team-member.tsx +++ b/components/team/team-member.tsx @@ -19,9 +19,9 @@ export default function TeamMember({ member, index }: TeamMemberProps) { return ( - + {/* Background Gradient */} -
+
{/* Avatar */}
diff --git a/components/team/team.tsx b/components/team/team.tsx index 731bc082..dd43de0e 100644 --- a/components/team/team.tsx +++ b/components/team/team.tsx @@ -1,4 +1,5 @@ import Image from "next/image"; +import { CursorGlow } from "@/components/ui/cursor-glow"; import { MotionSection, SlideIn } from "@/components/ui/motion/motion-components"; import { getTeamData } from "@/lib/team"; import TeamMember from "./team-member"; @@ -52,17 +53,19 @@ export default async function Team() { ))} ) : ( - - {section.members.map((member, index) => ( - - - - ))} - + + + {section.members.map((member, index) => ( + + + + ))} + + )}
))} diff --git a/components/ui/alert-box.tsx b/components/ui/alert-box.tsx index 3b6798dc..717551ee 100644 --- a/components/ui/alert-box.tsx +++ b/components/ui/alert-box.tsx @@ -23,11 +23,10 @@ const alertContainerVariants = cva( type: { info: "border border-blue-500/20 bg-blue-500/10 dark:border-blue-500/20 dark:bg-blue-500/10", warning: - "border border-yellow-500/20 bg-yellow-500/10 dark:border-yellow-500/20 dark:bg-yellow-500/10", + "border border-indigo-500/20 bg-indigo-500/10 dark:border-indigo-500/20 dark:bg-indigo-500/10", danger: "border border-red-500/20 bg-red-500/10 dark:border-red-500/20 dark:bg-red-500/10", - tip: "border border-green-500/20 bg-green-500/10 dark:border-green-500/20 dark:bg-green-500/10", - success: - "border border-emerald-500/20 bg-emerald-500/10 dark:border-emerald-500/20 dark:bg-emerald-500/10", + tip: "border border-blue-500/20 bg-blue-500/10 dark:border-blue-500/20 dark:bg-blue-500/10", + success: "border border-sky-500/20 bg-sky-500/10 dark:border-sky-500/20 dark:bg-sky-500/10", note: "border border-purple-500/20 bg-purple-500/10 dark:border-purple-500/20 dark:bg-purple-500/10", question: "border border-indigo-500/20 bg-indigo-500/10 dark:border-indigo-500/20 dark:bg-indigo-500/10", @@ -47,10 +46,10 @@ const alertIconVariants = cva("h-5 w-5", { variants: { type: { info: "text-blue-500 dark:text-blue-400", - warning: "text-yellow-500 dark:text-yellow-400", + warning: "text-indigo-500 dark:text-indigo-400", danger: "text-red-500 dark:text-red-400", - tip: "text-green-500 dark:text-green-400", - success: "text-emerald-500 dark:text-emerald-400", + tip: "text-blue-500 dark:text-blue-400", + success: "text-sky-500 dark:text-sky-400", note: "text-purple-500 dark:text-purple-400", question: "text-indigo-500 dark:text-indigo-400", important: "text-amber-500 dark:text-amber-400", @@ -66,10 +65,10 @@ const alertTextVariants = cva("prose-sm wrap-break-word md:prose-base max-w-full variants: { type: { info: "text-blue-800 dark:text-blue-200", - warning: "text-yellow-800 dark:text-yellow-200", + warning: "text-indigo-800 dark:text-indigo-200", danger: "text-red-800 dark:text-red-200", - tip: "text-green-800 dark:text-green-200", - success: "text-emerald-800 dark:text-emerald-200", + tip: "text-blue-800 dark:text-blue-200", + success: "text-sky-800 dark:text-sky-200", note: "text-purple-800 dark:text-purple-200", question: "text-indigo-800 dark:text-indigo-200", important: "text-amber-800 dark:text-amber-200", @@ -85,10 +84,10 @@ const alertTitleVariants = cva("mb-1 font-semibold text-sm md:text-base", { variants: { type: { info: "text-blue-900 dark:text-blue-100", - warning: "text-yellow-900 dark:text-yellow-100", + warning: "text-indigo-900 dark:text-indigo-100", danger: "text-red-900 dark:text-red-100", - tip: "text-green-900 dark:text-green-100", - success: "text-emerald-900 dark:text-emerald-100", + tip: "text-blue-900 dark:text-blue-100", + success: "text-sky-900 dark:text-sky-100", note: "text-purple-900 dark:text-purple-100", question: "text-indigo-900 dark:text-indigo-100", important: "text-amber-900 dark:text-amber-100", diff --git a/components/ui/button.tsx b/components/ui/button.tsx index 1e266c40..c08381bb 100644 --- a/components/ui/button.tsx +++ b/components/ui/button.tsx @@ -9,29 +9,30 @@ import { interactionSpring } from "@/lib/animations/variants"; import { cn } from "@/lib/utils"; const buttonVariants = cva( - "group relative inline-flex cursor-pointer select-none items-center justify-center overflow-visible font-medium transition-colors focus:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + "group relative inline-flex cursor-pointer select-none items-center justify-center overflow-visible font-semibold transition-all focus:outline-hidden focus-visible:ring-2 focus-visible:ring-[var(--ec-accent)] focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", { variants: { variant: { primary: - "border border-transparent bg-blue-600 text-white shadow-sm hover:bg-blue-700 hover:shadow-md dark:bg-blue-500 dark:hover:bg-blue-600", + "border border-transparent bg-[var(--ec-accent)] text-[var(--ec-accent-ink)] shadow-sm hover:shadow-md hover:brightness-105", secondary: - "border border-transparent bg-gray-100 text-gray-900 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700", + "border border-[var(--ec-line)] bg-[var(--ec-soft)] text-[var(--ec-text)] hover:brightness-95 dark:hover:brightness-125", outline: - "border border-gray-200 bg-transparent hover:bg-gray-50 hover:text-gray-900 dark:border-gray-700 dark:hover:bg-gray-800 dark:hover:text-white", - ghost: "border border-transparent bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800", - link: "h-auto border-transparent bg-transparent p-0 text-blue-600 underline-offset-4 hover:underline dark:text-blue-400", + "border border-[var(--ec-line)] bg-transparent text-[var(--ec-muted)] hover:bg-[var(--ec-soft)] hover:text-[var(--ec-text)]", + ghost: + "border border-transparent bg-transparent text-[var(--ec-muted)] hover:bg-[var(--ec-soft)] hover:text-[var(--ec-text)]", + link: "h-auto border-transparent bg-transparent p-0 text-[var(--ec-accent)] underline-offset-4 hover:underline", danger: "border border-transparent bg-red-600 text-white shadow-sm hover:bg-red-700 hover:shadow-red-500/20 dark:bg-red-700 dark:hover:bg-red-800", contrast: - "border border-transparent bg-gray-900 text-white shadow-sm hover:bg-gray-800 hover:shadow-lg dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100 dark:hover:shadow-blue-500/20", + "border border-transparent bg-[var(--ec-text)] text-[var(--ec-bg)] shadow-sm hover:bg-[var(--ec-accent)] hover:text-[var(--ec-accent-ink)] hover:shadow-lg", }, size: { xs: "h-7 rounded-md px-3 text-xs", sm: "h-9 rounded-lg px-4 text-sm", - md: "h-11 rounded-lg px-6 py-2 text-sm", - lg: "h-12 rounded-xl px-8 py-3 text-base", - xl: "h-14 rounded-xl px-10 py-4 text-lg", + md: "h-11 rounded-full px-6 py-2 text-sm", + lg: "h-12 rounded-full px-8 py-3 text-sm", + xl: "h-14 rounded-full px-10 py-4 text-base", }, fullWidth: { true: "w-full", diff --git a/components/ui/card.tsx b/components/ui/card.tsx index 3acbd7bc..e2b2d9d1 100644 --- a/components/ui/card.tsx +++ b/components/ui/card.tsx @@ -8,9 +8,10 @@ const Card = ({ }: React.HTMLAttributes & { ref?: React.Ref }) => (
diff --git a/components/ui/copy-to-clipboard.tsx b/components/ui/copy-to-clipboard.tsx index 2c870a53..79bfccf0 100644 --- a/components/ui/copy-to-clipboard.tsx +++ b/components/ui/copy-to-clipboard.tsx @@ -39,7 +39,7 @@ export function CopyToClipboard({ t.visible ? "translate-y-0 opacity-100" : "translate-y-3 opacity-0" )} > -
+
@@ -74,7 +74,7 @@ export function CopyToClipboard({ {showIcon ? ( {copied ? ( - + ) : ( )} diff --git a/components/ui/cursor-glow.tsx b/components/ui/cursor-glow.tsx new file mode 100644 index 00000000..6a5f3bab --- /dev/null +++ b/components/ui/cursor-glow.tsx @@ -0,0 +1,77 @@ +"use client"; + +import type { PointerEvent, ReactNode } from "react"; +import { useCallback, useRef } from "react"; +import { cn } from "@/lib/utils"; + +interface CursorGlowProps { + children: ReactNode; + className?: string; +} + +const GLOW_REACH = 180; + +export function CursorGlow({ children, className }: CursorGlowProps) { + const containerRef = useRef(null); + const frameRef = useRef(null); + + const updateCards = useCallback((clientX: number, clientY: number, active: boolean) => { + const container = containerRef.current; + if (!container) { + return; + } + + const cards = Array.from(container.querySelectorAll("[data-glow-card]")); + + for (const card of cards) { + if (!active) { + card.style.setProperty("--card-glow-opacity", "0"); + continue; + } + + const bounds = card.getBoundingClientRect(); + const distanceX = Math.max(bounds.left - clientX, 0, clientX - bounds.right); + const distanceY = Math.max(bounds.top - clientY, 0, clientY - bounds.bottom); + const distance = Math.hypot(distanceX, distanceY); + const opacity = Math.max(0, 1 - distance / GLOW_REACH); + + card.style.setProperty("--card-glow-x", `${clientX - bounds.left}px`); + card.style.setProperty("--card-glow-y", `${clientY - bounds.top}px`); + card.style.setProperty("--card-glow-opacity", opacity.toFixed(3)); + } + }, []); + + const handlePointerMove = useCallback( + (event: PointerEvent) => { + if (event.pointerType === "touch") { + return; + } + + if (frameRef.current !== null) { + cancelAnimationFrame(frameRef.current); + } + + const { clientX, clientY } = event; + frameRef.current = requestAnimationFrame(() => updateCards(clientX, clientY, true)); + }, + [updateCards] + ); + + const clearGlow = useCallback(() => { + if (frameRef.current !== null) { + cancelAnimationFrame(frameRef.current); + } + updateCards(0, 0, false); + }, [updateCards]); + + return ( +
+ {children} +
+ ); +} diff --git a/components/ui/mdx/badge.tsx b/components/ui/mdx/badge.tsx index a4b669b9..659bc92a 100644 --- a/components/ui/mdx/badge.tsx +++ b/components/ui/mdx/badge.tsx @@ -12,9 +12,9 @@ const badgeVariants = cva( default: "border-gray-200 bg-gray-100 text-gray-900 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100", success: - "border-green-200 bg-green-100 text-green-800 dark:border-green-800 dark:bg-green-900/30 dark:text-green-300", + "border-blue-200 bg-blue-100 text-blue-800 dark:border-blue-800 dark:bg-blue-900/30 dark:text-blue-300", warning: - "border-yellow-200 bg-yellow-100 text-yellow-800 dark:border-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-300", + "border-indigo-200 bg-indigo-100 text-indigo-800 dark:border-indigo-800 dark:bg-indigo-900/30 dark:text-indigo-300", danger: "border-red-200 bg-red-100 text-red-800 dark:border-red-800 dark:bg-red-900/30 dark:text-red-300", info: "border-blue-200 bg-blue-100 text-blue-800 dark:border-blue-800 dark:bg-blue-900/30 dark:text-blue-300", diff --git a/components/ui/mdx/before-after.tsx b/components/ui/mdx/before-after.tsx index b3157e36..e173f93a 100644 --- a/components/ui/mdx/before-after.tsx +++ b/components/ui/mdx/before-after.tsx @@ -164,14 +164,14 @@ export function BeforeAfterItem({ type, title, label, children }: BeforeAfterIte "flex items-center justify-between border-b px-4 py-3", isBefore ? "border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-900" - : "border-green-200 bg-green-50 dark:border-green-900 dark:bg-green-900" + : "border-blue-200 bg-blue-50 dark:border-blue-900 dark:bg-blue-900" )} >
{isBefore ? ( ) : ( - + )} {title ?? (isBefore ? "Before" : "After")}
@@ -182,7 +182,7 @@ export function BeforeAfterItem({ type, title, label, children }: BeforeAfterIte "rounded-full px-2 py-0.5 font-medium text-xs", isBefore ? "bg-red-100 text-red-700 dark:bg-red-800 dark:text-red-100" - : "bg-green-100 text-green-700 dark:bg-green-800 dark:text-green-100" + : "bg-blue-100 text-blue-700 dark:bg-blue-800 dark:text-blue-100" )} > {label} diff --git a/components/ui/mdx/code-block.tsx b/components/ui/mdx/code-block.tsx index 8145f7a9..0cb8c6a7 100644 --- a/components/ui/mdx/code-block.tsx +++ b/components/ui/mdx/code-block.tsx @@ -44,7 +44,7 @@ export const CodeBlock = memo(({ children, language: _language, className }: Cod text={textToCopy} > {({ copied }) => - copied ? : + copied ? : }
diff --git a/components/ui/mdx/command.tsx b/components/ui/mdx/command.tsx index b07cd57c..74d31e24 100644 --- a/components/ui/mdx/command.tsx +++ b/components/ui/mdx/command.tsx @@ -19,12 +19,12 @@ const variantStyles: Record = { light: "bg-gray-100 text-gray-900 dark:bg-gray-800 dark:text-gray-100", }, gradle: { - dark: "bg-gray-900 text-green-400 dark:bg-gray-900 dark:text-green-400", - light: "bg-green-50 text-green-700 dark:bg-green-900/30 dark:text-green-300", + dark: "bg-gray-900 text-blue-400 dark:bg-gray-900 dark:text-blue-400", + light: "bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300", }, maven: { - dark: "bg-gray-900 text-yellow-400 dark:bg-gray-900 dark:text-yellow-400", - light: "bg-yellow-50 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300", + dark: "bg-gray-900 text-indigo-400 dark:bg-gray-900 dark:text-indigo-400", + light: "bg-indigo-50 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300", }, npm: { dark: "bg-gray-900 text-red-400 dark:bg-gray-900 dark:text-red-400", @@ -100,7 +100,7 @@ export function Command({ > {({ copied }) => copied ? ( - + ) : ( ) diff --git a/components/ui/mdx/heading.tsx b/components/ui/mdx/heading.tsx index b9b10c15..ec83260c 100644 --- a/components/ui/mdx/heading.tsx +++ b/components/ui/mdx/heading.tsx @@ -39,7 +39,7 @@ export const Heading = ({ children, id, tag, className, ...props }: HeadingProps {({ copied }) => (
{copied ? ( - + ) : ( )} diff --git a/public/community/wumpus.png b/public/community/wumpus.png new file mode 100644 index 00000000..3dc30da0 Binary files /dev/null and b/public/community/wumpus.png differ