Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions apps/web/src/components/EntryHelpMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const ISSUES_URL = `${REPO}/issues/new`;
const PRS_URL = `${REPO}/pulls`;
const RELEASES_URL = `${REPO}/releases`;
const LATEST_RELEASE_URL = `${REPO}/releases/latest`;
const X_URL = 'https://x.com/nexudotio';
const DISCORD_URL = 'https://discord.gg/mHAjSMV6gz';

const ext = { target: '_blank', rel: 'noreferrer noopener' } as const;

Expand Down Expand Up @@ -178,6 +180,31 @@ export function EntryHelpMenu() {
</span>
<span>{t('entry.helpDownloadDesktop')}</span>
</a>
<div className="entry-help-popover__divider" aria-hidden />
<a
className="entry-help-popover__item"
href={X_URL}
{...ext}
role="menuitem"
onClick={() => setOpen(false)}
>
<span className="entry-help-popover__icon" aria-hidden>
<Icon name="external-link" size={14} />
</span>
<span>Follow @nexudotio on X</span>
</a>
<a
className="entry-help-popover__item"
href={DISCORD_URL}
{...ext}
role="menuitem"
onClick={() => setOpen(false)}
>
<span className="entry-help-popover__icon" aria-hidden>
<Icon name="discord" size={14} />
</span>
<span>Join Discord</span>
</a>
</div>
) : null}
</div>
Expand Down
57 changes: 28 additions & 29 deletions apps/web/src/components/EntryNavRail.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// Lovart-style left navigation rail for the entry view.
//
// Renders a narrow icon-only column. The first slot is the brand
// logo (clicking navigates to home), followed by primary
// actions (new project, home, projects, automations, plugins, design systems, integrations). A small
// help launcher sits at the bottom and opens a popover with the
// canonical "ask for help / submit a feature / what's new / download
// desktop" external links. Language switching and other account-
// scoped controls live behind the floating settings cog in the
// top-right corner of the main content.
// logo, which doubles as the Home destination: clicking it always
// navigates to home, and it carries the active `aria-current="page"`
// treatment when the home view is showing, so we do not need a
// separate Home button in the primary nav group. Primary actions
// (new project, projects, automations, design systems) follow.
// Secondary platform items (plugins, integrations) live in the footer
// section alongside the help launcher — they are accessible but visually
// de-emphasised relative to the daily-use primary destinations.
// Language switching and other account-scoped controls live behind the
// floating settings cog in the top-right corner of the main content.

import type { ReactNode } from 'react';
import { EntryHelpMenu } from './EntryHelpMenu';
Expand Down Expand Up @@ -58,16 +61,20 @@ function NavButton({ active, ariaLabel, tooltip, onClick, testId, children }: Na
export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
const t = useT();
const brandLabel = t('app.brand');
const homeLabel = t('entry.navHome');
const isHome = view === 'home';
const logoTooltip = isHome ? brandLabel : `${brandLabel} · ${homeLabel}`;

return (
<nav className="entry-nav-rail" aria-label="Primary">
<div className="entry-nav-rail__group">
<button
type="button"
className="entry-nav-rail__logo"
className={`entry-nav-rail__logo${isHome ? ' is-active' : ''}`}
onClick={() => onViewChange('home')}
aria-label={brandLabel}
data-tooltip={brandLabel}
aria-current={isHome ? 'page' : undefined}
data-tooltip={logoTooltip}
data-testid="entry-nav-logo"
>
<img
Expand All @@ -86,15 +93,6 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
>
<Icon name="plus" size={18} />
</NavButton>
<NavButton
active={view === 'home'}
ariaLabel={t('entry.navHome')}
tooltip={t('entry.navHome')}
onClick={() => onViewChange('home')}
testId="entry-nav-home"
>
<Icon name="home" size={18} />
</NavButton>
<NavButton
active={view === 'projects'}
ariaLabel={t('entry.navProjects')}
Expand All @@ -113,15 +111,6 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
>
<Icon name="kanban" size={18} />
</NavButton>
<NavButton
active={view === 'plugins'}
ariaLabel={t('entry.navPlugins')}
tooltip={t('entry.navPlugins')}
onClick={() => onViewChange('plugins')}
testId="entry-nav-plugins"
>
<Icon name="grid" size={18} />
</NavButton>
<NavButton
active={view === 'design-systems'}
ariaLabel={t('entry.navDesignSystems')}
Expand All @@ -131,6 +120,18 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
>
<Icon name="palette" size={18} />
</NavButton>
</div>
<div className="entry-nav-rail__footer">
<div className="entry-nav-rail__divider" role="separator" />
<NavButton
active={view === 'plugins'}
ariaLabel="Plugins"
tooltip="Plugins"
onClick={() => onViewChange('plugins')}
testId="entry-nav-plugins"
>
<Icon name="grid" size={18} />
</NavButton>
<NavButton
active={view === 'integrations'}
ariaLabel={t('entry.navIntegrations')}
Expand All @@ -140,8 +141,6 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
>
<Icon name="link" size={18} />
</NavButton>
</div>
<div className="entry-nav-rail__footer">
<EntryHelpMenu />
</div>
</nav>
Expand Down
Loading
Loading