mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Slight style changes
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
|
||||
<title>Sogen - Windows User Space Emulator</title>
|
||||
|
||||
<meta name="color-scheme" content="dark">
|
||||
<meta name="color-scheme" content="dark" />
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
|
||||
70
page/package-lock.json
generated
70
page/package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"@fontsource/inter": "^5.2.5",
|
||||
"@radix-ui/react-checkbox": "^1.2.3",
|
||||
"@radix-ui/react-dialog": "^1.1.11",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
||||
"@radix-ui/react-label": "^2.1.4",
|
||||
"@radix-ui/react-popover": "^1.1.11",
|
||||
"@radix-ui/react-scroll-area": "^1.2.6",
|
||||
@@ -1426,6 +1427,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dropdown-menu": {
|
||||
"version": "2.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.12.tgz",
|
||||
"integrity": "sha512-VJoMs+BWWE7YhzEQyVwvF9n22Eiyr83HotCVrMQzla/OwRovXCgah7AcaEr4hMNj4gJxSdtIbcHGvmJXOoJVHA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.2",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-menu": "2.1.12",
|
||||
"@radix-ui/react-primitive": "2.1.0",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-guards": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz",
|
||||
@@ -1507,6 +1537,46 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-menu": {
|
||||
"version": "2.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.12.tgz",
|
||||
"integrity": "sha512-+qYq6LfbiGo97Zz9fioX83HCiIYYFNs8zAsVCMQrIakoNYylIzWuoD/anAD3UzvvR6cnswmfRFJFq/zYYq/k7Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.2",
|
||||
"@radix-ui/react-collection": "1.1.4",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.7",
|
||||
"@radix-ui/react-focus-guards": "1.1.2",
|
||||
"@radix-ui/react-focus-scope": "1.1.4",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-popper": "1.2.4",
|
||||
"@radix-ui/react-portal": "1.1.6",
|
||||
"@radix-ui/react-presence": "1.1.4",
|
||||
"@radix-ui/react-primitive": "2.1.0",
|
||||
"@radix-ui/react-roving-focus": "1.1.7",
|
||||
"@radix-ui/react-slot": "1.2.0",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.11.tgz",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@fontsource/inter": "^5.2.5",
|
||||
"@radix-ui/react-checkbox": "^1.2.3",
|
||||
"@radix-ui/react-dialog": "^1.1.11",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
||||
"@radix-ui/react-label": "^2.1.4",
|
||||
"@radix-ui/react-popover": "^1.1.11",
|
||||
"@radix-ui/react-scroll-area": "^1.2.6",
|
||||
|
||||
@@ -4,8 +4,8 @@ html {
|
||||
|
||||
@media (pointer: fine) {
|
||||
::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
@@ -15,7 +15,7 @@ html {
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(97, 97, 97, 0.7);
|
||||
border-radius: 20px;
|
||||
border: 4px solid transparent;
|
||||
border: 6px solid transparent;
|
||||
background-clip: content-box;
|
||||
transition: all 0.1s linear;
|
||||
min-height: 50px;
|
||||
@@ -34,14 +34,47 @@ button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.resizable-cell,
|
||||
button.fancy-primary,
|
||||
button.fancy-secondary {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
button.fancy-primary {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(38, 144, 255, 1) 0%,
|
||||
rgba(0, 123, 255, 1) 100%
|
||||
);
|
||||
border: 1px solid rgb(18, 101, 236);
|
||||
text-shadow: rgba(0, 0, 0, 0.2) 0px 1px;
|
||||
}
|
||||
|
||||
button.fancy-primary:hover {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(46, 151, 255, 1) 0%,
|
||||
rgba(8, 130, 255, 1) 100%
|
||||
);
|
||||
border: 1px solid rgb(33, 33, 34);
|
||||
}
|
||||
|
||||
button.fancy-secondary {
|
||||
background: linear-gradient(180deg, rgb(38, 38, 39) 0%, rgb(34, 34, 35) 100%);
|
||||
border: 1px solid rgb(42, 42, 44);
|
||||
}
|
||||
|
||||
button.fancy-secondary:hover {
|
||||
background: linear-gradient(180deg, rgb(42, 42, 43) 0%, rgb(38, 38, 39) 100%);
|
||||
border: 1px solid rgb(33, 33, 34);
|
||||
}
|
||||
|
||||
.terminal-output span {
|
||||
padding: 4px;
|
||||
padding: 0px 16px;
|
||||
}
|
||||
|
||||
.terminal-output {
|
||||
font-weight: 600;
|
||||
font-size: 1.0em;
|
||||
font-size: 1.05em;
|
||||
font-family: monospace;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,14 @@ import {
|
||||
import { createDefaultSettings } from "./settings";
|
||||
import { SettingsMenu } from "@/components/settings-menu";
|
||||
|
||||
import { PlayFill, StopFill, GearFill, PauseFill } from "react-bootstrap-icons";
|
||||
import {
|
||||
PlayFill,
|
||||
StopFill,
|
||||
GearFill,
|
||||
PauseFill,
|
||||
FileEarmarkCheckFill,
|
||||
ImageFill,
|
||||
} from "react-bootstrap-icons";
|
||||
import { StatusIndicator } from "@/components/status-indicator";
|
||||
import { Header } from "./Header";
|
||||
import {
|
||||
@@ -32,6 +39,16 @@ import {
|
||||
ResizablePanelGroup,
|
||||
} from "@/components/ui/resizable";
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuGroup,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
function selectAndReadFile(): Promise<UserFile> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileInput = document.createElement("input");
|
||||
@@ -125,23 +142,52 @@ export function Playground() {
|
||||
<header className="flex shrink-0 items-center gap-2 border-b p-2 overflow-y-auto">
|
||||
<SidebarTrigger />
|
||||
<Separator orientation="vertical" className="h-4" />
|
||||
<Button size="sm" onClick={() => createEmulator()}>
|
||||
<PlayFill /> Run Sample
|
||||
|
||||
{/* RUN */}
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button size="sm">
|
||||
<PlayFill /> Run
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56">
|
||||
<DropdownMenuLabel>Run Application</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem onClick={() => createEmulator()}>
|
||||
<ImageFill className="mr-2" />
|
||||
<span>Select Sample</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => loadAndRunUserFile()}>
|
||||
<FileEarmarkCheckFill className="mr-2" />
|
||||
<span>Seelct your .exe</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<Button
|
||||
disabled={!emulator}
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => emulator?.stop()}
|
||||
>
|
||||
<StopFill /> Stop
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => loadAndRunUserFile()}>
|
||||
<PlayFill /> Run your .exe
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onClick={() => emulator?.stop()}>
|
||||
<StopFill /> Stop Emulation
|
||||
</Button>
|
||||
<Button size="sm" variant="secondary" onClick={toggleEmulatorState}>
|
||||
<Button
|
||||
size="sm"
|
||||
disabled={!emulator}
|
||||
variant="secondary"
|
||||
onClick={toggleEmulatorState}
|
||||
>
|
||||
{isEmulatorPaused() ? (
|
||||
<>
|
||||
<PlayFill /> Resume Emulation
|
||||
<PlayFill /> Resume
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<PauseFill /> Pause Emulation
|
||||
<PauseFill /> Pause
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
@@ -162,35 +208,8 @@ export function Playground() {
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col overflow-auto">
|
||||
<ResizablePanelGroup direction="horizontal" autoSaveId="debugger-panel-group">
|
||||
{/* Left */}
|
||||
<ResizablePanel className="resizable-cell">Disassembly</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
{/* Middle */}
|
||||
<ResizablePanel>
|
||||
<ResizablePanelGroup direction="vertical" autoSaveId="debugger-panel-middle-group">
|
||||
{/* Middle - Top */}
|
||||
<ResizablePanel>
|
||||
<Output ref={output} />
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
{/* Middle - Bottom */}
|
||||
<ResizablePanel className="resizable-cell">Memory</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
{/* Right */}
|
||||
<ResizablePanel>
|
||||
<ResizablePanelGroup direction="vertical" autoSaveId="debugger-panel-right-group">
|
||||
{/* Right - Top */}
|
||||
<ResizablePanel className="resizable-cell">Registers</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
{/* Right - Bottom */}
|
||||
<ResizablePanel className="resizable-cell">Stack</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
<div className="flex flex-1 flex-col overflow-auto pt-4">
|
||||
<Output ref={output} />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
|
||||
@@ -238,7 +238,7 @@ export class Output extends React.Component<OutputProps, FullOutputState> {
|
||||
width={this.state.width}
|
||||
height={this.state.height}
|
||||
itemCount={this.state.lines.length}
|
||||
itemSize={16}
|
||||
itemSize={20}
|
||||
>
|
||||
{({ index, style }) => {
|
||||
const line = this.state.lines[index];
|
||||
|
||||
@@ -10,13 +10,13 @@ const buttonVariants = cva(
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
||||
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 fancy-primary",
|
||||
destructive:
|
||||
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||
outline:
|
||||
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
||||
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80 fancy-secondary",
|
||||
ghost:
|
||||
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
|
||||
255
page/src/components/ui/dropdown-menu.tsx
Normal file
255
page/src/components/ui/dropdown-menu.tsx
Normal file
@@ -0,0 +1,255 @@
|
||||
import * as React from "react";
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||||
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function DropdownMenu({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
||||
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
||||
}
|
||||
|
||||
function DropdownMenuPortal({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Trigger
|
||||
data-slot="dropdown-menu-trigger"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuContent({
|
||||
className,
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<DropdownMenuPrimitive.Content
|
||||
data-slot="dropdown-menu-content"
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuItem({
|
||||
className,
|
||||
inset,
|
||||
variant = "default",
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean;
|
||||
variant?: "default" | "destructive";
|
||||
}) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Item
|
||||
data-slot="dropdown-menu-item"
|
||||
data-inset={inset}
|
||||
data-variant={variant}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuCheckboxItem({
|
||||
className,
|
||||
children,
|
||||
checked,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
data-slot="dropdown-menu-checkbox-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}
|
||||
>
|
||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuRadioGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.RadioGroup
|
||||
data-slot="dropdown-menu-radio-group"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuRadioItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
data-slot="dropdown-menu-radio-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<CircleIcon className="size-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuLabel({
|
||||
className,
|
||||
inset,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Label
|
||||
data-slot="dropdown-menu-label"
|
||||
data-inset={inset}
|
||||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
data-slot="dropdown-menu-separator"
|
||||
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuShortcut({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<"span">) {
|
||||
return (
|
||||
<span
|
||||
data-slot="dropdown-menu-shortcut"
|
||||
className={cn(
|
||||
"text-muted-foreground ml-auto text-xs tracking-widest",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuSub({
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
||||
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
||||
}
|
||||
|
||||
function DropdownMenuSubTrigger({
|
||||
className,
|
||||
inset,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
data-slot="dropdown-menu-sub-trigger"
|
||||
data-inset={inset}
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRightIcon className="ml-auto size-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
function DropdownMenuSubContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
||||
return (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
data-slot="dropdown-menu-sub-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuSubContent,
|
||||
};
|
||||
Reference in New Issue
Block a user