dropdown-menu

User profile dropdown menu with theme toggle and status selector

User profile dropdown menu with theme toggle and status selector

Загрузка превью…

src/dropdown-menu/c-dropdown-menu-14.vue

<!--
  Расхождение с апстримом: `IconPlaceholder` заменена инлайновым `<svg>`
  (lucide-react v0.545.0 "chevrons-up-down"/"sun"/"moon"/"monitor"/
  "building"/"phone"/"check"/"settings"/"life-buoy"/"log-out") — см.
  docs/PORTING.md §5. Сетевое изображение github.com/shadcn.png заменено
  локальным 1x1 data-URI (`PIXEL`).
-->
<script setup lang="ts">
import { computed, ref } from "vue"
import { Badge } from "@/components/reui/badge"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"

const PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAUwAOw=="

const statuses = [
  { value: "available", label: "Available", color: "bg-green-500" },
  { value: "away", label: "Away", color: "bg-amber-500" },
  { value: "busy", label: "Busy", color: "bg-red-500" },
  { value: "offline", label: "Offline", color: "bg-gray-400" },
]

const status = ref("available")
const theme = ref("light")

const activeStatus = computed(() => statuses.find((s) => s.value === status.value) || statuses[0]!)
</script>

<template>
  <div class="flex items-center justify-center">
    <DropdownMenu>
      <DropdownMenuTrigger as-child>
        <Button variant="outline" class="w-40">
          <Avatar class="size-4">
            <AvatarImage :src="PIXEL" />
            <AvatarFallback>CN</AvatarFallback>
          </Avatar>
          <span class="text-sm font-medium">shadcn</span>

          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-chevrons-up-down ml-auto opacity-60">
            <path d="m7 15 5 5 5-5" />
            <path d="m7 9 5-5 5 5" />
          </svg>
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent class="w-60" align="start" :side-offset="8">
        <div class="flex items-center gap-3 px-1 pt-1.5">
          <Avatar class="size-8">
            <AvatarImage :src="PIXEL" />
            <AvatarFallback>CN</AvatarFallback>
          </Avatar>
          <div class="flex flex-col">
            <span class="text-foreground text-sm font-medium">shadcn</span>
            <span class="text-muted-foreground text-xs">ui@shadcn.com</span>
          </div>
        </div>
        <div class="py-2.5">
          <Tabs v-model="theme">
            <TabsList class="w-full">
              <TabsTrigger value="light" class="h-6 flex-1">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-sun size-4">
                  <circle cx="12" cy="12" r="4" />
                  <path d="M12 2v2" />
                  <path d="M12 20v2" />
                  <path d="m4.93 4.93 1.41 1.41" />
                  <path d="m17.66 17.66 1.41 1.41" />
                  <path d="M2 12h2" />
                  <path d="M20 12h2" />
                  <path d="m6.34 17.66-1.41 1.41" />
                  <path d="m19.07 4.93-1.41 1.41" />
                </svg>
              </TabsTrigger>
              <TabsTrigger value="dark" class="h-6 flex-1">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-moon size-4">
                  <path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401" />
                </svg>
              </TabsTrigger>
              <TabsTrigger value="system" class="h-6 flex-1">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-monitor size-4">
                  <rect width="20" height="14" x="2" y="3" rx="2" />
                  <line x1="8" x2="16" y1="21" y2="21" />
                  <line x1="12" x2="12" y1="17" y2="21" />
                </svg>
              </TabsTrigger>
            </TabsList>
          </Tabs>
        </div>
        <DropdownMenuGroup>
          <DropdownMenuItem class="justify-between" @select="(e: Event) => e.preventDefault()">
            <span class="flex items-center gap-2">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-building">
                <path d="M12 10h.01" />
                <path d="M12 14h.01" />
                <path d="M12 6h.01" />
                <path d="M16 10h.01" />
                <path d="M16 14h.01" />
                <path d="M16 6h.01" />
                <path d="M8 10h.01" />
                <path d="M8 14h.01" />
                <path d="M8 6h.01" />
                <path d="M9 22v-3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v3" />
                <rect x="4" y="2" width="16" height="20" rx="2" />
              </svg>
              Your Companies
            </span>
            <Badge variant="secondary" size="sm" class="rounded-full px-1.5">12</Badge>
          </DropdownMenuItem>
          <DropdownMenuItem class="justify-between" @select="(e: Event) => e.preventDefault()">
            <span class="flex items-center gap-2">
              <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-phone">
                <path d="M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384" />
              </svg>
              Your Numbers
            </span>
            <Badge variant="secondary" size="sm" class="rounded-full px-1.5">2</Badge>
          </DropdownMenuItem>
        </DropdownMenuGroup>
        <DropdownMenuSub>
          <DropdownMenuSubTrigger>
            <span class="flex items-center gap-2">
              <span class="size-2 rounded-full" :class="activeStatus.color" />
              {{ activeStatus.label }}
            </span>
          </DropdownMenuSubTrigger>
          <DropdownMenuSubContent class="w-40">
            <DropdownMenuItem v-for="s in statuses" :key="s.value" class="justify-between" @click="status = s.value">
              <span class="flex items-center gap-2">
                <span class="size-2 rounded-full" :class="s.color" />
                {{ s.label }}
              </span>
              <svg v-if="status === s.value" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-check text-muted-foreground size-4">
                <path d="M20 6 9 17l-5-5" />
              </svg>
            </DropdownMenuItem>
          </DropdownMenuSubContent>
        </DropdownMenuSub>
        <DropdownMenuSeparator />
        <DropdownMenuGroup>
          <DropdownMenuItem>
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-settings">
              <path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" />
              <circle cx="12" cy="12" r="3" />
            </svg>
            Settings
          </DropdownMenuItem>
          <DropdownMenuItem>
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-life-buoy">
              <circle cx="12" cy="12" r="10" />
              <path d="m4.93 4.93 4.24 4.24" />
              <path d="m14.83 9.17 4.24-4.24" />
              <path d="m14.83 14.83 4.24 4.24" />
              <path d="m9.17 14.83-4.24 4.24" />
              <circle cx="12" cy="12" r="4" />
            </svg>
            Help Center
          </DropdownMenuItem>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuItem variant="destructive">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-log-out">
            <path d="m16 17 5-5-5-5" />
            <path d="M21 12H9" />
            <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
          </svg>
          Logout
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  </div>
</template>

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/c-dropdown-menu-14.json

Зависимости реестра

Источник: порт из ReUI (Keenthemes, MIT)