Frontend: - replace the i18next stack with a small typed i18n module - hero clouds removed, llms.txt, HUD widget ARIA fixes and tests Mod: - TargetESP constellation mode; tracker and colors extracted - JumpCircles: 7 new shapes, shared animation and color pipeline - KillEffect blood mode with Burst/Fountain/Ring/Spray styles - main menu: menuLayout setting (orbs/hero) and hero screen - Simple Voice Chat soft integration: VoiceChat module and HUD panel - renderer/quick: static Draw facade with glass outline - vanilla chat: Baritone-style autocomplete popup for the % command prefix
56 lines
2 KiB
TypeScript
56 lines
2 KiB
TypeScript
import type { Dispatch } from 'react'
|
|
import { useTranslation } from '@shared/i18n/react'
|
|
import type { GuiAction, GuiState } from '../demo'
|
|
import { Icon } from '../parts/Glyphs'
|
|
import { type Category, CATEGORIES } from '../parts/modules'
|
|
|
|
type Props = { state: GuiState; dispatch: Dispatch<GuiAction> }
|
|
|
|
/** `ModulesMenuScreen`: the four liquid-glass category panels, side by side. */
|
|
export function ModulesScreen({ state, dispatch }: Props) {
|
|
const { t } = useTranslation('clickgui')
|
|
return (
|
|
<div className="lv-gui-panels" role="list" aria-label={t('categories')}>
|
|
{CATEGORIES.map((c) => (
|
|
<Panel key={c.id} category={c} state={state} dispatch={dispatch} />
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function Panel({ category, state, dispatch }: { category: Category } & Props) {
|
|
const { t } = useTranslation('clickgui')
|
|
const titleId = `lv-gui-panel-${category.id}`
|
|
return (
|
|
<div role="listitem" className="lv-gui-panel" data-category={category.id} aria-labelledby={titleId}>
|
|
<header className="lv-gui-panel-head">
|
|
<h2 id={titleId} className="lv-gui-panel-title">
|
|
{category.name}
|
|
</h2>
|
|
<Icon name={category.id} className="lv-gui-panel-icon" />
|
|
</header>
|
|
<ul className="lv-gui-rows">
|
|
{category.modules.map((m) => {
|
|
const on = Boolean(state.enabled[m.name])
|
|
return (
|
|
<li key={m.name}>
|
|
<button
|
|
type="button"
|
|
className="lv-gui-row"
|
|
data-on={on}
|
|
data-demo={`module:${m.name}`}
|
|
aria-pressed={on}
|
|
title={t('module', { name: m.name })}
|
|
onClick={() => dispatch({ type: 'toggle', module: m.name })}
|
|
onContextMenu={(e) => e.preventDefault()}
|
|
>
|
|
<span className="lv-gui-row-name">{m.name}</span>
|
|
{on && <Icon name="check" className="lv-gui-row-check" />}
|
|
</button>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
</div>
|
|
)
|
|
}
|