Desktop: custom context menus everywhere, never the browser's menu
One ContextMenu in the design system (keyboard, type-ahead, submenus, check items, disabled reasons, Shift+F10 / Menu key, viewport placement, light and dark). The native menu is prevented globally; text fields keep Cut / Copy / Paste / Select all. Menus on sidebar and portfolio apps, app hero, releases, store art, live art, reviews, checks, editor fields, catalog, prices, accounts, app folders, ignored.
This commit is contained in:
parent
944b24fe59
commit
dece83c3e8
23 changed files with 839 additions and 28 deletions
|
|
@ -24,6 +24,8 @@ import { type Command, Palette } from './ui/Palette';
|
|||
import { ExportMenu, useExportItems, useRunExport } from './ui/Exports';
|
||||
import { ErrorBoundary } from './ui/ErrorBoundary';
|
||||
import { Toasts } from './ui/Toasts';
|
||||
import { useContextMenu } from './ui/ContextMenu';
|
||||
import { appMenu } from './ui/app-menu';
|
||||
import { worstTone } from './ui/ds';
|
||||
import { attention } from './lib/model';
|
||||
|
||||
|
|
@ -149,6 +151,7 @@ export function App({ onTheme }: { onTheme: () => void }) {
|
|||
const groups = d.studios.length ? groupByStudio(listed.map(a => ({ app: a })), d.studios) : [{ studio: null as string | null, rows: listed.map(a => ({ app: a })) }];
|
||||
const ignoredCount = d.apps.filter(a => a.ignored).length + d.overrides.ignored.filter(i => i.startsWith('account:')).length;
|
||||
|
||||
const menu = useContextMenu();
|
||||
const appItem = (a: UnifiedApp) => {
|
||||
const e = d.statusFor(a);
|
||||
const missing = !!a.project?.missing;
|
||||
|
|
@ -156,7 +159,7 @@ export function App({ onTheme }: { onTheme: () => void }) {
|
|||
const bad = missing ? 1 : (e?.errors.length ?? 0) + (e?.check?.problems.length ?? 0);
|
||||
return (
|
||||
<div role="listitem" key={a.key}>
|
||||
<button className={`nav nav-app${a.ignored ? ' is-ignored' : ''}`} aria-current={current({ screen: 'app', appId: a.key, tab: 'releases' })}
|
||||
<button {...menu(() => appMenu(a, d, nav, { showIgnored }))} className={`nav nav-app${a.ignored ? ' is-ignored' : ''}`} aria-current={current({ screen: 'app', appId: a.key, tab: 'releases' })}
|
||||
onClick={() => go({ screen: 'app', appId: a.key, tab: route.screen === 'app' && tabsFor(!!a.project).includes(route.tab) ? route.tab : 'releases' })}>
|
||||
<span className="ds-side-ic"><AppIcon name={a.name} src={d.iconFor(a)} />{tone && <span className={`ds-sdot ${tone}`} role="img" aria-label={tone === 'bad' ? t('pf.blocker') : tone === 'warn' ? t('pf.warning') : t('pf.note')} />}</span>
|
||||
<span className="grow">{a.name}</span>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue