feat: add DropdownMenu component
feat: add DropdownMenu component feat: add DropdownMenu component
This commit is contained in:
parent
f59d7727b2
commit
edbdeca603
|
|
@ -6,6 +6,7 @@ import AlertDialogDemo from '@/registry/default/examples/AlertDialogDemo.vue'
|
|||
import SelectDemo from '@/registry/default/examples/SelectDemo.vue'
|
||||
import AvatarDemo from '@/registry/default/examples/AvatarDemo.vue'
|
||||
import AlertDemo from '@/registry/default/examples/AlertDemo.vue'
|
||||
import DropdownMenuDemo from '@/registry/default/examples/DropdownMenuDemo.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -23,5 +24,7 @@ import AlertDemo from '@/registry/default/examples/AlertDemo.vue'
|
|||
<AvatarDemo />
|
||||
|
||||
<AlertDemo />
|
||||
|
||||
<DropdownMenuDemo />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
110
apps/www/src/lib/registry/default/examples/DropdownMenuDemo.vue
Normal file
110
apps/www/src/lib/registry/default/examples/DropdownMenuDemo.vue
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<script setup lang="ts">
|
||||
import { Button } from "@/registry/default/ui/button";
|
||||
import { DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger,
|
||||
DropdownMenuItem, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuPortal, DropdownMenuSubContent, DropdownMenu
|
||||
} from "@/registry/default/ui/dropdown-menu";
|
||||
import {
|
||||
Cloud,
|
||||
CreditCard,
|
||||
Github,
|
||||
Keyboard,
|
||||
LifeBuoy,
|
||||
LogOut,
|
||||
Mail,
|
||||
MessageSquare,
|
||||
Plus,
|
||||
PlusCircle,
|
||||
Settings,
|
||||
User,
|
||||
UserPlus,
|
||||
Users,
|
||||
} from "lucide-vue-next"
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline">Open Dropdown Menu</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent class="w-56">
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<User class="mr-2 h-4 w-4" />
|
||||
<span>Profile</span>
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<CreditCard class="mr-2 h-4 w-4" />
|
||||
<span>Billing</span>
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Settings class="mr-2 h-4 w-4" />
|
||||
<span>Settings</span>
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<Keyboard class="mr-2 h-4 w-4" />
|
||||
<span>Keyboard shortcuts</span>
|
||||
<DropdownMenuShortcut>⌘K</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<Users class="mr-2 h-4 w-4" />
|
||||
<span>Team</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<UserPlus class="mr-2 h-4 w-4" />
|
||||
<span>Invite users</span>
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem>
|
||||
<Mail class="mr-2 h-4 w-4" />
|
||||
<span>Email</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<MessageSquare class="mr-2 h-4 w-4" />
|
||||
<span>Message</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<PlusCircle class="mr-2 h-4 w-4" />
|
||||
<span>More...</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuPortal>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuItem>
|
||||
<Plus class="mr-2 h-4 w-4" />
|
||||
<span>New Team</span>
|
||||
<DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<Github class="mr-2 h-4 w-4" />
|
||||
<span>GitHub</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<LifeBuoy class="mr-2 h-4 w-4" />
|
||||
<span>Support</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem disabled>
|
||||
<Cloud class="mr-2 h-4 w-4" />
|
||||
<span>API</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<LogOut class="mr-2 h-4 w-4" />
|
||||
<span>Log out</span>
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuCheckboxItem as DropdownMenuCheckboxItemPrimitive, type DropdownMenuCheckboxItemProps, type DropdownMenuCheckboxItemEmits,
|
||||
DropdownMenuItemIndicator as DropdownMenuItemIndicatorPrimitive } from 'radix-vue';
|
||||
import { cn, useEmitAsProps } from '@/utils';
|
||||
import { CheckIcon } from 'lucide-vue-next';
|
||||
|
||||
const props = defineProps<DropdownMenuCheckboxItemProps>();
|
||||
const emits = defineEmits<DropdownMenuCheckboxItemEmits>();
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuCheckboxItem',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuCheckboxItemPrimitive
|
||||
:class="cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
:checked="checked"
|
||||
v-bind="{ ...attrs.rest, ...props, ...emitsAsProps }">
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuItemIndicatorPrimitive>
|
||||
<CheckIcon class="h-4 w-4" />
|
||||
</DropdownMenuItemIndicatorPrimitive>
|
||||
</span>
|
||||
<slot />
|
||||
</DropdownMenuCheckboxItemPrimitive>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuContent as DropdownMenuContentPrimitive, type DropdownMenuContentProps, type DropdownMenuContentEmits } from 'radix-vue';
|
||||
import { cn, useEmitAsProps } from '@/utils';
|
||||
import { DropdownMenuPortal } from '@/registry/default/ui/dropdown-menu';
|
||||
|
||||
const props = withDefaults(defineProps<DropdownMenuContentProps>(), {
|
||||
sideOffset: 4,
|
||||
});
|
||||
const emits = defineEmits<DropdownMenuContentEmits>();
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuContent',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuContentPrimitive
|
||||
:class="cn(
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
|
||||
'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',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest, ...props, ...emitsAsProps }">
|
||||
<slot />
|
||||
</DropdownMenuContentPrimitive>
|
||||
</DropdownMenuPortal>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuItem as DropdownMenuItemPrimitive, type DropdownMenuItemProps, type DropdownMenuItemEmits } from 'radix-vue';
|
||||
import { cn, useEmitAsProps } from '@/utils';
|
||||
|
||||
const props = defineProps<DropdownMenuItemProps & {
|
||||
inset?: boolean
|
||||
}>();
|
||||
const emits = defineEmits<DropdownMenuItemEmits>();
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuItem',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuItemPrimitive
|
||||
:class="cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
inset && 'pl-8',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest, ...props, ...emitsAsProps }">
|
||||
<slot />
|
||||
</DropdownMenuItemPrimitive>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuLabel as DropdownMenuLabelPrimitive, type DropdownMenuLabelProps } from 'radix-vue';
|
||||
import { cn } from '@/utils';
|
||||
|
||||
const props = defineProps<DropdownMenuLabelProps & {
|
||||
inset?: boolean
|
||||
}>();
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuLabel',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuLabelPrimitive
|
||||
:class="cn(
|
||||
'px-2 py-1.5 text-sm font-semibold',
|
||||
inset && 'pl-8',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest, ...props }">
|
||||
<slot />
|
||||
</DropdownMenuLabelPrimitive>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuRadioItem as DropdownMenuRadioItemPrimitive, type DropdownMenuRadioItemProps, type DropdownMenuRadioItemEmits,
|
||||
DropdownMenuItemIndicator as DropdownMenuItemIndicatorPrimitive } from 'radix-vue';
|
||||
import { cn, useEmitAsProps } from '@/utils';
|
||||
import { CircleIcon } from 'lucide-vue-next';
|
||||
|
||||
const props = defineProps<DropdownMenuRadioItemProps>();
|
||||
const emits = defineEmits<DropdownMenuRadioItemEmits>();
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuRadioItem',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuRadioItemPrimitive
|
||||
:class="cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest, ...props, ...emitsAsProps }">
|
||||
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuItemIndicatorPrimitive>
|
||||
<CircleIcon class="h-4 w-4 fill-current" />
|
||||
</DropdownMenuItemIndicatorPrimitive>
|
||||
</span>
|
||||
<slot />
|
||||
</DropdownMenuRadioItemPrimitive>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuSeparator as DropdownMenuSeparatorPrimitive, type DropdownMenuSeparatorProps } from 'radix-vue';
|
||||
import { cn } from '@/utils';
|
||||
|
||||
const props = defineProps<DropdownMenuSeparatorProps>();
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuSeparator',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuSeparatorPrimitive
|
||||
:class="cn(
|
||||
'mx-1 my-1 h-px bg-muted',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest, ...props }">
|
||||
<slot />
|
||||
</DropdownMenuSeparatorPrimitive>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { cn } from '@/utils';
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuShortcut',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
:class="cn(
|
||||
'ml-auto text-xs tracking-widest opacity-60',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest }">
|
||||
<slot />
|
||||
</span>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuSubContent as DropdownMenuSubContentPrimitive, type DropdownMenuSubContentProps, type DropdownMenuSubContentEmits } from 'radix-vue';
|
||||
import { cn, useEmitAsProps } from '@/utils';
|
||||
|
||||
const props = defineProps<DropdownMenuSubContentProps>();
|
||||
const emits = defineEmits<DropdownMenuSubContentEmits>();
|
||||
const emitsAsProps = useEmitAsProps(emits);
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuSubContent',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuSubContentPrimitive
|
||||
:class="cn(
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest, ...props, ...emitsAsProps }">
|
||||
<slot />
|
||||
</DropdownMenuSubContentPrimitive>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import { DropdownMenuSubTrigger as DropdownMenuSubTriggerPrimitive, type DropdownMenuSubTriggerProps } from 'radix-vue';
|
||||
import { cn } from '@/utils';
|
||||
import { ChevronRight } from 'lucide-vue-next';
|
||||
|
||||
const props = defineProps<DropdownMenuSubTriggerProps & {
|
||||
inset?: boolean;
|
||||
}>();
|
||||
|
||||
defineOptions({
|
||||
name: 'DropdownMenuSubTrigger',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const allAttrs = useAttrs()
|
||||
const attrs = computed(() => {
|
||||
const { class: className, ...rest } = allAttrs
|
||||
return {
|
||||
className,
|
||||
rest: rest
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DropdownMenuSubTriggerPrimitive
|
||||
:class="cn(
|
||||
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
|
||||
inset && 'pl-8',
|
||||
attrs.className ?? '',
|
||||
)"
|
||||
v-bind="{ ...attrs.rest, ...props }">
|
||||
<slot />
|
||||
<ChevronRight class="ml-auto w-4 h-4" />
|
||||
</DropdownMenuSubTriggerPrimitive>
|
||||
</template>
|
||||
42
apps/www/src/lib/registry/default/ui/dropdown-menu/index.ts
Normal file
42
apps/www/src/lib/registry/default/ui/dropdown-menu/index.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import {
|
||||
DropdownMenuRoot as DropdownMenuRootPrimitive,
|
||||
DropdownMenuTrigger as DropdownMenuTriggerPrimitive,
|
||||
DropdownMenuGroup as DropdownMenuGroupPrimitive,
|
||||
DropdownMenuPortal as DropdownMenuPortalPrimitive,
|
||||
DropdownMenuSub as DropdownMenuSubPrimitive,
|
||||
DropdownMenuRadioGroup as DropdownMenuRadioGroupPrimitive,
|
||||
} from "radix-vue"
|
||||
import DropdownMenuSubTrigger from "./DropdownMenuSubTrigger.vue"
|
||||
import DropdownMenuSubContent from "./DropdownMenuSubContent.vue"
|
||||
import DropdownMenuContent from "./DropdownMenuContent.vue"
|
||||
import DropdownMenuItem from "./DropdownMenuItem.vue"
|
||||
import DropdownMenuCheckboxItem from "./DropdownMenuCheckboxItem.vue"
|
||||
import DropdownMenuRadioItem from "./DropdownMenuRadioItem.vue"
|
||||
import DropdownMenuLabel from "./DropdownMenuLabel.vue"
|
||||
import DropdownMenuSeparator from "./DropdownMenuSeparator.vue"
|
||||
import DropdownMenuShortcut from "./DropdownMenuShortcut.vue"
|
||||
|
||||
const DropdownMenu = DropdownMenuRootPrimitive
|
||||
const DropdownMenuTrigger = DropdownMenuTriggerPrimitive
|
||||
const DropdownMenuGroup = DropdownMenuGroupPrimitive
|
||||
const DropdownMenuPortal = DropdownMenuPortalPrimitive
|
||||
const DropdownMenuSub = DropdownMenuSubPrimitive
|
||||
const DropdownMenuRadioGroup = DropdownMenuRadioGroupPrimitive
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user