feat(app): project context menu on right-click
This commit is contained in:
@@ -31,6 +31,7 @@ import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip"
|
||||
import { HoverCard } from "@opencode-ai/ui/hover-card"
|
||||
import { MessageNav } from "@opencode-ai/ui/message-nav"
|
||||
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
|
||||
import { ContextMenu } from "@opencode-ai/ui/context-menu"
|
||||
import { Collapsible } from "@opencode-ai/ui/collapsible"
|
||||
import { DiffChanges } from "@opencode-ai/ui/diff-changes"
|
||||
import { Spinner } from "@opencode-ai/ui/spinner"
|
||||
@@ -2310,10 +2311,13 @@ export default function Layout(props: ParentProps) {
|
||||
() => props.project.vcs === "git" && layout.sidebar.workspaces(props.project.worktree)(),
|
||||
)
|
||||
const [open, setOpen] = createSignal(false)
|
||||
const [menu, setMenu] = createSignal(false)
|
||||
|
||||
const preview = createMemo(() => !props.mobile && layout.sidebar.opened())
|
||||
const overlay = createMemo(() => !props.mobile && !layout.sidebar.opened())
|
||||
const active = createMemo(() => (preview() ? open() : overlay() && state.hoverProject === props.project.worktree))
|
||||
const active = createMemo(
|
||||
() => menu() || (preview() ? open() : overlay() && state.hoverProject === props.project.worktree),
|
||||
)
|
||||
|
||||
createEffect(() => {
|
||||
if (preview()) return
|
||||
@@ -2352,35 +2356,79 @@ export default function Layout(props: ParentProps) {
|
||||
|
||||
const projectName = () => props.project.name || getFilename(props.project.worktree)
|
||||
const trigger = (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={projectName()}
|
||||
data-action="project-switch"
|
||||
data-project={base64Encode(props.project.worktree)}
|
||||
classList={{
|
||||
"flex items-center justify-center size-10 p-1 rounded-lg overflow-hidden transition-colors cursor-default": true,
|
||||
"bg-transparent border-2 border-icon-strong-base hover:bg-surface-base-hover": selected(),
|
||||
"bg-transparent border border-transparent hover:bg-surface-base-hover hover:border-border-weak-base":
|
||||
!selected() && !active(),
|
||||
"bg-surface-base-hover border border-border-weak-base": !selected() && active(),
|
||||
<ContextMenu
|
||||
modal={!sidebarHovering()}
|
||||
onOpenChange={(value) => {
|
||||
setMenu(value)
|
||||
if (value) setOpen(false)
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
if (!overlay()) return
|
||||
globalSync.child(props.project.worktree)
|
||||
setState("hoverProject", props.project.worktree)
|
||||
setState("hoverSession", undefined)
|
||||
}}
|
||||
onFocus={() => {
|
||||
if (!overlay()) return
|
||||
globalSync.child(props.project.worktree)
|
||||
setState("hoverProject", props.project.worktree)
|
||||
setState("hoverSession", undefined)
|
||||
}}
|
||||
onClick={() => navigateToProject(props.project.worktree)}
|
||||
onBlur={() => setOpen(false)}
|
||||
>
|
||||
<ProjectIcon project={props.project} notify />
|
||||
</button>
|
||||
<ContextMenu.Trigger
|
||||
as="button"
|
||||
type="button"
|
||||
aria-label={projectName()}
|
||||
data-action="project-switch"
|
||||
data-project={base64Encode(props.project.worktree)}
|
||||
classList={{
|
||||
"flex items-center justify-center size-10 p-1 rounded-lg overflow-hidden transition-colors cursor-default": true,
|
||||
"bg-transparent border-2 border-icon-strong-base hover:bg-surface-base-hover": selected(),
|
||||
"bg-transparent border border-transparent hover:bg-surface-base-hover hover:border-border-weak-base":
|
||||
!selected() && !active(),
|
||||
"bg-surface-base-hover border border-border-weak-base": !selected() && active(),
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
if (!overlay()) return
|
||||
globalSync.child(props.project.worktree)
|
||||
setState("hoverProject", props.project.worktree)
|
||||
setState("hoverSession", undefined)
|
||||
}}
|
||||
onFocus={() => {
|
||||
if (!overlay()) return
|
||||
globalSync.child(props.project.worktree)
|
||||
setState("hoverProject", props.project.worktree)
|
||||
setState("hoverSession", undefined)
|
||||
}}
|
||||
onClick={() => navigateToProject(props.project.worktree)}
|
||||
onBlur={() => setOpen(false)}
|
||||
>
|
||||
<ProjectIcon project={props.project} notify />
|
||||
</ContextMenu.Trigger>
|
||||
<ContextMenu.Portal mount={!props.mobile ? state.nav : undefined}>
|
||||
<ContextMenu.Content>
|
||||
<ContextMenu.Item onSelect={() => dialog.show(() => <DialogEditProject project={props.project} />)}>
|
||||
<ContextMenu.ItemLabel>{language.t("common.edit")}</ContextMenu.ItemLabel>
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item
|
||||
data-action="project-workspaces-toggle"
|
||||
data-project={base64Encode(props.project.worktree)}
|
||||
disabled={props.project.vcs !== "git" && !layout.sidebar.workspaces(props.project.worktree)()}
|
||||
onSelect={() => {
|
||||
const enabled = layout.sidebar.workspaces(props.project.worktree)()
|
||||
if (enabled) {
|
||||
layout.sidebar.toggleWorkspaces(props.project.worktree)
|
||||
return
|
||||
}
|
||||
if (props.project.vcs !== "git") return
|
||||
layout.sidebar.toggleWorkspaces(props.project.worktree)
|
||||
}}
|
||||
>
|
||||
<ContextMenu.ItemLabel>
|
||||
{layout.sidebar.workspaces(props.project.worktree)()
|
||||
? language.t("sidebar.workspaces.disable")
|
||||
: language.t("sidebar.workspaces.enable")}
|
||||
</ContextMenu.ItemLabel>
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Separator />
|
||||
<ContextMenu.Item
|
||||
data-action="project-close-menu"
|
||||
data-project={base64Encode(props.project.worktree)}
|
||||
onSelect={() => closeProject(props.project.worktree)}
|
||||
>
|
||||
<ContextMenu.ItemLabel>{language.t("common.close")}</ContextMenu.ItemLabel>
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Portal>
|
||||
</ContextMenu>
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -2388,13 +2436,14 @@ export default function Layout(props: ParentProps) {
|
||||
<div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
|
||||
<Show when={preview()} fallback={trigger}>
|
||||
<HoverCard
|
||||
open={open()}
|
||||
open={open() && !menu()}
|
||||
openDelay={0}
|
||||
closeDelay={0}
|
||||
placement="right-start"
|
||||
gutter={6}
|
||||
trigger={trigger}
|
||||
onOpenChange={(value) => {
|
||||
if (menu()) return
|
||||
setOpen(value)
|
||||
if (value) setState("hoverSession", undefined)
|
||||
}}
|
||||
|
||||
134
packages/ui/src/components/context-menu.css
Normal file
134
packages/ui/src/components/context-menu.css
Normal file
@@ -0,0 +1,134 @@
|
||||
[data-component="context-menu-content"],
|
||||
[data-component="context-menu-sub-content"] {
|
||||
min-width: 8rem;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-xs-border);
|
||||
background-clip: padding-box;
|
||||
background-color: var(--surface-raised-stronger-non-alpha);
|
||||
padding: 4px;
|
||||
z-index: 100;
|
||||
transform-origin: var(--kb-menu-content-transform-origin);
|
||||
|
||||
&:focus-within,
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
animation: contextMenuContentHide var(--transition-duration) var(--transition-easing) forwards;
|
||||
|
||||
@starting-style {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
&[data-expanded] {
|
||||
pointer-events: auto;
|
||||
animation: contextMenuContentShow var(--transition-duration) var(--transition-easing) forwards;
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="context-menu-content"],
|
||||
[data-component="context-menu-sub-content"] {
|
||||
[data-slot="context-menu-item"],
|
||||
[data-slot="context-menu-checkbox-item"],
|
||||
[data-slot="context-menu-radio-item"],
|
||||
[data-slot="context-menu-sub-trigger"] {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 4px 8px;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: default;
|
||||
outline: none;
|
||||
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: var(--font-size-base);
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-strong);
|
||||
|
||||
transition-property: background-color, color;
|
||||
transition-duration: var(--transition-duration);
|
||||
transition-timing-function: var(--transition-easing);
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--surface-raised-base-hover);
|
||||
}
|
||||
|
||||
&[data-disabled] {
|
||||
color: var(--text-weak);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="context-menu-sub-trigger"] {
|
||||
&[data-expanded] {
|
||||
background: var(--surface-raised-base-hover);
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="context-menu-item-indicator"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
[data-slot="context-menu-item-label"] {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
[data-slot="context-menu-item-description"] {
|
||||
font-size: var(--font-size-x-small);
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
[data-slot="context-menu-separator"] {
|
||||
height: 1px;
|
||||
margin: 4px -4px;
|
||||
border-top-color: var(--border-weak-base);
|
||||
}
|
||||
|
||||
[data-slot="context-menu-group-label"] {
|
||||
padding: 4px 8px;
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: var(--font-size-x-small);
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--line-height-large);
|
||||
letter-spacing: var(--letter-spacing-normal);
|
||||
color: var(--text-weak);
|
||||
}
|
||||
|
||||
[data-slot="context-menu-arrow"] {
|
||||
fill: var(--surface-raised-stronger-non-alpha);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes contextMenuContentShow {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes contextMenuContentHide {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scaleY(0.95);
|
||||
}
|
||||
}
|
||||
308
packages/ui/src/components/context-menu.tsx
Normal file
308
packages/ui/src/components/context-menu.tsx
Normal file
@@ -0,0 +1,308 @@
|
||||
import { ContextMenu as Kobalte } from "@kobalte/core/context-menu"
|
||||
import { splitProps } from "solid-js"
|
||||
import type { ComponentProps, ParentProps } from "solid-js"
|
||||
|
||||
export interface ContextMenuProps extends ComponentProps<typeof Kobalte> {}
|
||||
export interface ContextMenuTriggerProps extends ComponentProps<typeof Kobalte.Trigger> {}
|
||||
export interface ContextMenuIconProps extends ComponentProps<typeof Kobalte.Icon> {}
|
||||
export interface ContextMenuPortalProps extends ComponentProps<typeof Kobalte.Portal> {}
|
||||
export interface ContextMenuContentProps extends ComponentProps<typeof Kobalte.Content> {}
|
||||
export interface ContextMenuArrowProps extends ComponentProps<typeof Kobalte.Arrow> {}
|
||||
export interface ContextMenuSeparatorProps extends ComponentProps<typeof Kobalte.Separator> {}
|
||||
export interface ContextMenuGroupProps extends ComponentProps<typeof Kobalte.Group> {}
|
||||
export interface ContextMenuGroupLabelProps extends ComponentProps<typeof Kobalte.GroupLabel> {}
|
||||
export interface ContextMenuItemProps extends ComponentProps<typeof Kobalte.Item> {}
|
||||
export interface ContextMenuItemLabelProps extends ComponentProps<typeof Kobalte.ItemLabel> {}
|
||||
export interface ContextMenuItemDescriptionProps extends ComponentProps<typeof Kobalte.ItemDescription> {}
|
||||
export interface ContextMenuItemIndicatorProps extends ComponentProps<typeof Kobalte.ItemIndicator> {}
|
||||
export interface ContextMenuRadioGroupProps extends ComponentProps<typeof Kobalte.RadioGroup> {}
|
||||
export interface ContextMenuRadioItemProps extends ComponentProps<typeof Kobalte.RadioItem> {}
|
||||
export interface ContextMenuCheckboxItemProps extends ComponentProps<typeof Kobalte.CheckboxItem> {}
|
||||
export interface ContextMenuSubProps extends ComponentProps<typeof Kobalte.Sub> {}
|
||||
export interface ContextMenuSubTriggerProps extends ComponentProps<typeof Kobalte.SubTrigger> {}
|
||||
export interface ContextMenuSubContentProps extends ComponentProps<typeof Kobalte.SubContent> {}
|
||||
|
||||
function ContextMenuRoot(props: ContextMenuProps) {
|
||||
return <Kobalte {...props} data-component="context-menu" />
|
||||
}
|
||||
|
||||
function ContextMenuTrigger(props: ParentProps<ContextMenuTriggerProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.Trigger
|
||||
{...rest}
|
||||
data-slot="context-menu-trigger"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuIcon(props: ParentProps<ContextMenuIconProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.Icon
|
||||
{...rest}
|
||||
data-slot="context-menu-icon"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.Icon>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuPortal(props: ContextMenuPortalProps) {
|
||||
return <Kobalte.Portal {...props} />
|
||||
}
|
||||
|
||||
function ContextMenuContent(props: ParentProps<ContextMenuContentProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.Content
|
||||
{...rest}
|
||||
data-component="context-menu-content"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.Content>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuArrow(props: ContextMenuArrowProps) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList"])
|
||||
return (
|
||||
<Kobalte.Arrow
|
||||
{...rest}
|
||||
data-slot="context-menu-arrow"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuSeparator(props: ContextMenuSeparatorProps) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList"])
|
||||
return (
|
||||
<Kobalte.Separator
|
||||
{...rest}
|
||||
data-slot="context-menu-separator"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuGroup(props: ParentProps<ContextMenuGroupProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.Group
|
||||
{...rest}
|
||||
data-slot="context-menu-group"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.Group>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuGroupLabel(props: ParentProps<ContextMenuGroupLabelProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.GroupLabel
|
||||
{...rest}
|
||||
data-slot="context-menu-group-label"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.GroupLabel>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuItem(props: ParentProps<ContextMenuItemProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.Item
|
||||
{...rest}
|
||||
data-slot="context-menu-item"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.Item>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuItemLabel(props: ParentProps<ContextMenuItemLabelProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.ItemLabel
|
||||
{...rest}
|
||||
data-slot="context-menu-item-label"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.ItemLabel>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuItemDescription(props: ParentProps<ContextMenuItemDescriptionProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.ItemDescription
|
||||
{...rest}
|
||||
data-slot="context-menu-item-description"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.ItemDescription>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuItemIndicator(props: ParentProps<ContextMenuItemIndicatorProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.ItemIndicator
|
||||
{...rest}
|
||||
data-slot="context-menu-item-indicator"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.ItemIndicator>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuRadioGroup(props: ParentProps<ContextMenuRadioGroupProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.RadioGroup
|
||||
{...rest}
|
||||
data-slot="context-menu-radio-group"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.RadioGroup>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuRadioItem(props: ParentProps<ContextMenuRadioItemProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.RadioItem
|
||||
{...rest}
|
||||
data-slot="context-menu-radio-item"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.RadioItem>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuCheckboxItem(props: ParentProps<ContextMenuCheckboxItemProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.CheckboxItem
|
||||
{...rest}
|
||||
data-slot="context-menu-checkbox-item"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.CheckboxItem>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuSub(props: ContextMenuSubProps) {
|
||||
return <Kobalte.Sub {...props} />
|
||||
}
|
||||
|
||||
function ContextMenuSubTrigger(props: ParentProps<ContextMenuSubTriggerProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.SubTrigger
|
||||
{...rest}
|
||||
data-slot="context-menu-sub-trigger"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.SubTrigger>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuSubContent(props: ParentProps<ContextMenuSubContentProps>) {
|
||||
const [local, rest] = splitProps(props, ["class", "classList", "children"])
|
||||
return (
|
||||
<Kobalte.SubContent
|
||||
{...rest}
|
||||
data-component="context-menu-sub-content"
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
>
|
||||
{local.children}
|
||||
</Kobalte.SubContent>
|
||||
)
|
||||
}
|
||||
|
||||
export const ContextMenu = Object.assign(ContextMenuRoot, {
|
||||
Trigger: ContextMenuTrigger,
|
||||
Icon: ContextMenuIcon,
|
||||
Portal: ContextMenuPortal,
|
||||
Content: ContextMenuContent,
|
||||
Arrow: ContextMenuArrow,
|
||||
Separator: ContextMenuSeparator,
|
||||
Group: ContextMenuGroup,
|
||||
GroupLabel: ContextMenuGroupLabel,
|
||||
Item: ContextMenuItem,
|
||||
ItemLabel: ContextMenuItemLabel,
|
||||
ItemDescription: ContextMenuItemDescription,
|
||||
ItemIndicator: ContextMenuItemIndicator,
|
||||
RadioGroup: ContextMenuRadioGroup,
|
||||
RadioItem: ContextMenuRadioItem,
|
||||
CheckboxItem: ContextMenuCheckboxItem,
|
||||
Sub: ContextMenuSub,
|
||||
SubTrigger: ContextMenuSubTrigger,
|
||||
SubContent: ContextMenuSubContent,
|
||||
})
|
||||
@@ -16,6 +16,7 @@
|
||||
@import "../components/collapsible.css" layer(components);
|
||||
@import "../components/diff.css" layer(components);
|
||||
@import "../components/diff-changes.css" layer(components);
|
||||
@import "../components/context-menu.css" layer(components);
|
||||
@import "../components/dropdown-menu.css" layer(components);
|
||||
@import "../components/dialog.css" layer(components);
|
||||
@import "../components/file-icon.css" layer(components);
|
||||
|
||||
Reference in New Issue
Block a user