Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
87 lines
2.9 KiB
TypeScript
87 lines
2.9 KiB
TypeScript
import { X } from 'lucide-react';
|
|
|
|
import { useI18n } from '../../application/i18n/I18nProvider';
|
|
import {
|
|
requestOpenPluginView,
|
|
usePluginViewLifecycle,
|
|
} from '../../application/state/usePluginViewLifecycle';
|
|
import { Button } from '../ui/button';
|
|
import { PluginContributionIcon } from './PluginContributionIcon';
|
|
|
|
export { requestOpenPluginView };
|
|
|
|
const DEFAULT_KEYBINDING_CONTEXT = Object.freeze({ 'netcatty.surface': 'keybinding' });
|
|
|
|
export function PluginContributionHost({
|
|
locale,
|
|
theme,
|
|
themeTokens: suppliedThemeTokens,
|
|
keybindingContext = DEFAULT_KEYBINDING_CONTEXT,
|
|
}: {
|
|
locale: string;
|
|
theme: string;
|
|
themeTokens?: Record<string, string>;
|
|
keybindingContext?: Record<string, unknown>;
|
|
}) {
|
|
const { t } = useI18n();
|
|
const {
|
|
activeView,
|
|
close,
|
|
effectiveRequested,
|
|
mountRef,
|
|
} = usePluginViewLifecycle({
|
|
locale,
|
|
theme,
|
|
suppliedThemeTokens,
|
|
keybindingContext,
|
|
});
|
|
|
|
if (!effectiveRequested || !activeView) return null;
|
|
const location = activeView.view.location;
|
|
const containerClass = location === 'aside'
|
|
? 'absolute inset-y-0 right-0 z-40 w-[420px] border-l border-border bg-background shadow-2xl'
|
|
: location === 'panel'
|
|
? 'absolute inset-x-0 bottom-0 z-40 h-[42%] border-t border-border bg-background shadow-2xl'
|
|
: location === 'modal'
|
|
? 'fixed left-1/2 top-1/2 z-50 h-[70vh] w-[min(800px,85vw)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-border bg-background shadow-2xl'
|
|
: 'absolute inset-0 z-40 bg-background';
|
|
|
|
if (location === 'tab') {
|
|
return (
|
|
<section className={`${containerClass} flex flex-col`} role="region" aria-label={activeView.view.title}>
|
|
<div ref={mountRef} className="min-h-0 flex-1" />
|
|
</section>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<section
|
|
className={`${containerClass} flex flex-col`}
|
|
role={location === 'modal' ? 'dialog' : 'region'}
|
|
aria-modal={location === 'modal' ? true : undefined}
|
|
aria-label={activeView.view.title}
|
|
>
|
|
<header className="app-no-drag flex h-11 shrink-0 items-center justify-between border-b border-border px-3">
|
|
<div className="flex min-w-0 items-center gap-2">
|
|
<PluginContributionIcon pluginId={activeView.plugin.id} icon={activeView.view.icon} className="shrink-0" />
|
|
<div className="min-w-0">
|
|
<div className="truncate text-sm font-medium">{activeView.view.title}</div>
|
|
<div className="truncate text-[10px] text-muted-foreground">{activeView.plugin.displayName}</div>
|
|
</div>
|
|
</div>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className="h-7 w-7"
|
|
onClick={() => void close()}
|
|
aria-label={t('common.close')}
|
|
autoFocus={location === 'modal'}
|
|
>
|
|
<X size={14} />
|
|
</Button>
|
|
</header>
|
|
<div ref={mountRef} className="min-h-0 flex-1" />
|
|
</section>
|
|
);
|
|
}
|