feat(homepage): enhance localization and integrate loading label for code snippet

- Added 'loadingLabel' to the Props type in GregCoreRandomSnippet for dynamic loading text.
- Updated English localization to include 'codeSnippetLoading' for improved user experience.
- Modified the homepage to utilize the new loading label in the GregCoreRandomSnippet component, enhancing clarity during content loading.

This commit improves the user interface by providing a more informative loading state for code snippets.
This commit is contained in:
Marvin
2026-04-10 04:03:23 +02:00
parent b8df049b4e
commit 533c7a2729
5 changed files with 130 additions and 90 deletions

View File

@@ -3,8 +3,8 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
import {GREG_CORE_SNIPPETS} from '../data/gregCoreSnippets';
type Props = {
/** e.g. "Random sample from gregCore" */
caption: string;
loadingLabel: string;
};
/**
@@ -51,7 +51,7 @@ export function GregCoreRandomSnippet(props: Props): JSX.Element {
aria-busy
>
<div className="flex min-h-[280px] items-center justify-center rounded-lg bg-surface-container-lowest p-6">
<span className="text-sm text-on-surface-variant">Loading code sample</span>
<span className="text-sm text-on-surface-variant">{props.loadingLabel}</span>
</div>
</div>
}>

View File

@@ -1,62 +1,68 @@
import type { HomepageContent } from './types';
import { homepageShellEn } from './sharedLinks';
import type {HomepageContent} from './types';
import {homepageShellEn} from './sharedLinks';
export const en: HomepageContent = {
...homepageShellEn,
heroLine1: 'DATACENTER MODDING HUB.',
heroLine2: 'SMART LIKE GREG.',
heroSub1: 'Install mods, use the Workshop, fix common issues — without digging through engine docs.',
heroSub2: 'Technical reference for authors lives under Developers in the wiki.',
ctaStart: 'HELP FOR PLAYERS',
ctaMods: 'MOD CATALOG',
ctaModManager: 'DOWNLOAD MOD MANAGER',
modManagerSectionTitle: 'GregModManager',
heroLine1: 'Play with mods.',
heroLine2: 'Ship with confidence.',
heroSub1:
'Player guides cover install, Workshop, and common fixes—without engine deep dives.',
heroSub2: 'Authors get hooks, APIs, and repo layout under Developers in the wiki.',
ctaStart: 'Player guides',
ctaMods: 'Mod catalog',
ctaModManager: 'Download Greg Mod Manager',
modManagerSectionTitle: 'Greg Mod Manager',
modManagerSectionBody:
'The Gregtools desktop app for Workshop browsing, uploads, dependency checks, and project metadata. Builds are published on GitHub — use the button below to open the latest release (the URL always tracks the newest version).',
'Desktop app from the Gregtools project: Workshop browsing, installs, dependency checks, and project metadata. The download button opens GitHubs latest release (the URL always points at the newest build).',
modManagerDownloadLabel: 'Download latest release',
modManagerLatestHint:
'Uses GitHubs /releases/latest redirect so you always land on the current release assets.',
docsPaths: 'Documentation paths',
featureTitles: ['Play with mods', 'Workshop & updates', 'Clear docs', 'Community'],
modManagerLatestHint: 'Uses GitHubs /releases/latest redirect so you always get current assets.',
docsPaths: 'Documentation',
featureTitles: [
'Player-first guides',
'Workshop and updates',
'Structured wiki',
'Community',
],
featureDescriptions: [
'Step-by-step paths for installing and troubleshooting — no repo jargon on day one.',
'GregModManager and release channels explain where builds come from.',
'A few flat player pages up top; author pages stay under Developers.',
'Discord and GitHub for help — framework internals only when you need them.',
'Step-by-step install and troubleshooting. No repository jargon on day one.',
'Greg Mod Manager and the release-channels page explain where mods are published.',
'Short paths for players; technical depth lives under Developers.',
'Discord and GitHub for support—dig into gregCore only when you need to.',
],
comingSoon: 'Coming soon',
comingSoonText:
'`datacentermods.com` is in preparation. Until launch, use the wiki **For players** and the **Mod catalog**.',
communityTitle: 'Community & maintainers',
communityText: 'This portal is designed for gregFramework docs and community-built plugins across the Data Center ecosystem.',
docsEndUserTitle: 'End-user',
'datacentermods.com is in preparation. Until it launches, use the player guides in the wiki and the mod catalog on this site.',
communityTitle: 'Community',
communityText:
'This site documents gregFramework, community mods, and plugins for Data Center Simulator.',
docsEndUserTitle: 'Players',
docsEndUserDescription: 'Install, update, FAQ, troubleshooting.',
docsModDevsTitle: 'Mod developers',
docsModDevsDescription: 'Debug workflows, setup, hooks and references.',
docsModDevsDescription: 'Setup, debugging, hooks, and references.',
docsContributorsTitle: 'Contributors',
docsContributorsDescription: 'Conventions, CI checks, contribution workflow.',
docsContributorsDescription: 'Conventions, CI, and docs workflow.',
docsCapabilityTitle: 'Capability matrix',
docsCapabilityDescription: 'Complete feature map and implementation use cases.',
ecosystemTitle: 'Ecosystem coverage',
docsCapabilityDescription: 'Feature map and implementation notes.',
ecosystemTitle: 'Ecosystem',
ecosystemCoreTitle: 'gregFramework core',
ecosystemCoreDescription: 'Hook system, FFI bridge, event contracts and runtime architecture.',
ecosystemCoreCta: 'Open core docs',
ecosystemRustTitle: 'Standalone Rust',
ecosystemRustDescription: 'Rust/FFI implementation guides for external and standalone runtimes.',
ecosystemRustCta: 'Open Rust/FFI docs',
ecosystemMultiplayerTitle: 'Multiplayer & plugins',
ecosystemMultiplayerDescription: 'Multiplayer roadmap, plugin docs, and community module references.',
ecosystemMultiplayerCta: 'Open multiplayer docs',
gregTitle: 'The legend of Greg',
ecosystemCoreDescription: 'Hooks, events, optional FFI bridge, and runtime architecture.',
ecosystemCoreCta: 'Open core docs',
ecosystemRustTitle: 'Rust and FFI',
ecosystemRustDescription: 'Guides for external and standalone runtimes.',
ecosystemRustCta: 'Open Rust / FFI docs',
ecosystemMultiplayerTitle: 'Multiplayer and plugins',
ecosystemMultiplayerDescription: 'Roadmap, plugin docs, and related modules.',
ecosystemMultiplayerCta: 'Open multiplayer docs',
gregTitle: 'Greg',
gregText1:
'Greg is the tireless server technician of this project. He looks like he has not slept for months, and he is usually quiet — but once a rack fails or a mod breaks, Greg is already there.',
'Greg is the projects mascot: the technician who shows up when a rack misbehaves or a build breaks. Calm, practical, slightly tired.',
gregText2:
'He quietly fulfills your wishes: more uptime, cleaner configs, better logs and less deployment drama. He does not ask much, he just ships.',
gregQuote: '"Be smart. Be like Greg."',
supportTitle: 'Support',
supportText: 'Report bugs, request docs for new community plugins, and track workstreams.',
supportCta: 'Open GitHub issues',
availableModsLabel: 'Available mods',
repositoryLabel: 'Repository',
joinLabel: 'JOIN',
'The framework tries to be the same—clear docs, predictable hooks, less guesswork when you mod or maintain.',
gregQuote: 'Be smart. Be like Greg.',
supportTitle: 'Issues and feedback',
supportText: 'Report bugs, suggest doc improvements, and follow work on GitHub.',
supportCta: 'GitHub issues',
availableModsLabel: 'Mod catalog',
repositoryLabel: 'gregFramework on GitHub',
joinLabel: 'Discord',
};

View File

@@ -1,41 +1,49 @@
import type {HomepageContent, HomepageDocLink} from './types';
/** Player-first links — technical docs live under /wiki/developers */
/** Player-facing wiki entry points */
export const sharedKnowledgeLinksEn: HomepageDocLink[] = [
{title: 'Wiki home', description: 'Short entry — players vs developers.', link: '/wiki'},
{
title: 'For players',
description: 'Install, update, troubleshooting.',
title: 'Wiki home',
description: 'Overview: players, authors, and where each topic lives.',
link: '/wiki',
},
{
title: 'Player guides',
description: 'Install mods, updates, troubleshooting, and FAQs.',
link: '/wiki/guides/players/overview',
},
{
title: 'GregModManager',
description: 'Browse, install, and manage Workshop mods (Gregtools desktop app).',
title: 'Greg Mod Manager',
description: 'Desktop app for the Workshop: browse, install, and manage mods.',
link: '/wiki/guides/players/enduser-workshop',
},
{
title: 'Release channels',
description: 'Steam Workshop vs GitHub for builds.',
description: 'Where builds come from: Steam Workshop and GitHub.',
link: '/wiki/reference/release-channels',
},
{title: 'Mod catalog', description: 'Modules with docs and download links.', link: '/mods'},
{
title: 'Mod catalog',
description: 'Listings with docs, versions, and download links.',
link: '/mods',
},
];
/** Authors & contributors — one hop to the full technical tree */
/** Authors and repo contributors */
export const sharedWorkflowLinksEn: HomepageDocLink[] = [
{
title: 'Developers (hub)',
description: 'Framework, mods, plugins, reference, roadmap — all technical links.',
title: 'Developers hub',
description: 'Framework, hooks, plugins, reference material, and roadmap.',
link: '/wiki/developers',
},
{
title: 'Mod developer guide',
description: 'Hooks, setup, and workflow entry.',
description: 'MelonLoader setup, gregCore hooks, and workflow.',
link: '/wiki/guides/mod-developers/overview',
},
{
title: 'Contributor workflow',
description: 'Docs site and repo conventions.',
description: 'How this docs site and the repos are maintained.',
link: '/wiki/contributors/docusaurus-workflow',
},
];
@@ -50,24 +58,33 @@ export const homepageShellEn: Pick<
| 'codeSectionTitle'
| 'codeSectionLead'
| 'codeSnippetCaption'
| 'codeSnippetLoading'
| 'codeSectionBullets'
| 'ctaDiscordTitle'
| 'ctaDiscordLead'
| 'ctaDiscordButton'
| 'knowledgeLinks'
| 'workflowLinks'
> = {
heroBadge: 'gregFramework · docs live',
heroBadge: 'Documentation · Data Center modding',
heroBrandLine1: 'greg',
heroBrandLine2Gradient: 'Framework',
knowledgeSectionTitle: 'Players — start here',
workflowSectionTitle: 'Authors & contributors',
codeSectionTitle: 'Building on gregFramework',
knowledgeSectionTitle: 'Start here',
workflowSectionTitle: 'For authors and contributors',
codeSectionTitle: 'How mods connect to the game',
codeSectionLead:
'C# mods on MelonLoader, Harmony hooks in gregCore, and optional Rust bridges — author details are under Developers.',
codeSnippetCaption: 'Random sample from gregCore',
ctaDiscordTitle: 'Community',
ctaDiscordLead: 'Questions about playing or building — ask in Discord.',
ctaDiscordButton: 'Join Discord',
'Mods use MelonLoader and Harmony. gregCore turns game methods into stable greg.* events your code can subscribe to—details are under Developers.',
codeSnippetCaption: 'Random excerpt from gregCore',
codeSnippetLoading: 'Loading code sample…',
codeSectionBullets: [
'gregCore patches the game and emits typed greg.* hook names (see greg_hooks.json).',
'The wiki and catalog list each mod with releases and dependencies.',
'Source is split across repos (for example gregCore, gregMods, gregExtensions, gregWiki).',
],
ctaDiscordTitle: 'Questions?',
ctaDiscordLead:
'Ask in Discord for install issues, mod compatibility, or help building on gregFramework.',
ctaDiscordButton: 'Open Discord',
knowledgeLinks: sharedKnowledgeLinksEn,
workflowLinks: sharedWorkflowLinksEn,
};

View File

@@ -25,8 +25,12 @@ export type HomepageContent = {
workflowSectionTitle: string;
codeSectionTitle: string;
codeSectionLead: string;
/** Homepage #code — random gregCore excerpt */
/** Homepage #code — random gregCore excerpt (card title) */
codeSnippetCaption: string;
/** Shown while BrowserOnly mounts */
codeSnippetLoading: string;
/** Three bullets beside the gregCore snippet */
codeSectionBullets: [string, string, string];
ctaDiscordTitle: string;
ctaDiscordLead: string;
ctaDiscordButton: string;

View File

@@ -21,6 +21,26 @@ const GREG_MODMANAGER_LATEST =
const viewport = {once: true, margin: '-90px'};
/** Inline `greg_hooks.json` in copy when the string contains that token. */
function formatBulletWithOptionalCode(text: string): React.ReactNode {
if (!text.includes('greg_hooks.json')) {
return text;
}
const parts = text.split('greg_hooks.json');
return (
<>
{parts.map((part, i) => (
<React.Fragment key={i}>
{part}
{i < parts.length - 1 ? (
<code className="text-xs">greg_hooks.json</code>
) : null}
</React.Fragment>
))}
</>
);
}
function buildVariants(reducedMotion: boolean) {
const section: Variants = reducedMotion
? {hidden: {opacity: 0}, show: {opacity: 1}}
@@ -81,7 +101,7 @@ export default function HomePage(): JSX.Element {
return (
<Layout
title="Home"
description="Help for Data Center players using mods — plus developer docs under /wiki/developers."
description="gregFramework documentation: player guides, mod catalog, and developer references for Data Center Simulator."
>
<main className="bg-background text-on-surface font-sans min-h-screen editorial-bleed bg-hero-gradient">
<section className="hero-motion-wrap relative flex min-h-[72vh] flex-col items-center justify-center overflow-hidden px-4 py-24 text-center">
@@ -301,27 +321,20 @@ export default function HomePage(): JSX.Element {
{t.codeSectionLead}
</p>
<ul className="space-y-4 text-on-surface-variant">
<li className="flex items-start gap-3">
<span className="material-symbols-outlined mt-0.5 text-primary">
{t.codeSectionBullets.map((line) => (
<li key={line} className="flex items-start gap-3">
<span className="material-symbols-outlined mt-0.5 shrink-0 text-primary">
check_circle
</span>
<span>MelonLoader + Harmony: gregCore emits typed <code className="text-xs">greg.*</code> events</span>
</li>
<li className="flex items-start gap-3">
<span className="material-symbols-outlined mt-0.5 text-primary">
check_circle
</span>
<span>Plugins and mods documented beside release metadata</span>
</li>
<li className="flex items-start gap-3">
<span className="material-symbols-outlined mt-0.5 text-primary">
check_circle
</span>
<span>Split repos: gregCore, gregMods, gregExtensions, gregWiki</span>
<span>{formatBulletWithOptionalCode(line)}</span>
</li>
))}
</ul>
</div>
<GregCoreRandomSnippet caption={t.codeSnippetCaption} />
<GregCoreRandomSnippet
caption={t.codeSnippetCaption}
loadingLabel={t.codeSnippetLoading}
/>
</div>
</motion.section>