button-group

Button group with select controls

Button group with select controls

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

src/button-group/c-button-group-33.vue

<script setup lang="ts">
import { ref } from "vue"
import { ButtonGroup } from "@/components/ui/button-group"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from "@/components/ui/select"

const environments = [
  { value: "production", label: "Production", icon: "globe" },
  { value: "staging", label: "Staging", icon: "layers" },
  { value: "development", label: "Development", icon: "terminal" },
]

const timeRanges = [
  { value: "1h", label: "Last hour", category: "recent" },
  { value: "6h", label: "Last 6 hours", category: "recent" },
  { value: "12h", label: "Last 12 hours", category: "recent" },
  { value: "24h", label: "Last 24 hours", category: "recent" },
  { value: "3d", label: "Last 3 days", category: "plus" },
  { value: "7d", label: "Last 7 days", category: "plus" },
  { value: "14d", label: "Last 14 days", category: "plus" },
  { value: "30d", label: "Last 30 days", category: "plus" },
]

const env = ref("development")
const range = ref("12h")

function findEnv(value: unknown) {
  return environments.find((item) => item.value === value)
}
</script>

<template>
  <ButtonGroup>
    <Select v-model="env">
      <SelectTrigger class="w-40">
        <!--
          reka-ui's SelectValue отдаёт только textContent выбранного
          SelectItem, тогда как Radix's Select.Value заново монтирует
          children целиком (см. docs/PORTING.md §5, packages/blocks/src/
          select/c-select-6.vue) — иконка пропадала бы молча.
        -->
        <SelectValue placeholder="Select environment">
          <template #default="{ modelValue }">
            <div v-if="findEnv(modelValue)" class="flex items-center gap-2">
              <svg
                v-if="findEnv(modelValue)!.icon === 'globe'"
                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-globe size-3.5 opacity-60"
              >
                <circle cx="12" cy="12" r="10" />
                <path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
                <path d="M2 12h20" />
              </svg>
              <svg
                v-else-if="findEnv(modelValue)!.icon === 'layers'"
                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-layers size-3.5 opacity-60"
              >
                <path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z" />
                <path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12" />
                <path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17" />
              </svg>
              <svg
                v-else
                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-terminal size-3.5 opacity-60"
              >
                <path d="M12 19h8" />
                <path d="m4 17 6-6-6-6" />
              </svg>
              <span>{{ findEnv(modelValue)!.label }}</span>
            </div>
          </template>
        </SelectValue>
      </SelectTrigger>
      <SelectContent position="popper" align="start">
        <SelectGroup>
          <SelectItem
            v-for="item in environments"
            :key="item.value"
            :value="item.value"
          >
            <div class="flex items-center gap-2">
              <svg
                v-if="item.icon === 'globe'"
                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-globe size-3.5 opacity-60"
              >
                <circle cx="12" cy="12" r="10" />
                <path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
                <path d="M2 12h20" />
              </svg>
              <svg
                v-else-if="item.icon === 'layers'"
                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-layers size-3.5 opacity-60"
              >
                <path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z" />
                <path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12" />
                <path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17" />
              </svg>
              <svg
                v-else
                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-terminal size-3.5 opacity-60"
              >
                <path d="M12 19h8" />
                <path d="m4 17 6-6-6-6" />
              </svg>
              <span>{{ item.label }}</span>
            </div>
          </SelectItem>
        </SelectGroup>
      </SelectContent>
    </Select>

    <Select v-model="range">
      <SelectTrigger class="w-40">
        <SelectValue placeholder="Select range" />
      </SelectTrigger>
      <SelectContent position="popper">
        <SelectGroup>
          <SelectItem
            v-for="item in timeRanges.filter((r) => r.category === 'recent')"
            :key="item.value"
            :value="item.value"
          >
            {{ item.label }}
          </SelectItem>
        </SelectGroup>
        <SelectSeparator />
        <SelectGroup>
          <SelectLabel>Observability Plus</SelectLabel>
          <SelectItem
            v-for="item in timeRanges.filter((r) => r.category === 'plus')"
            :key="item.value"
            :value="item.value"
          >
            {{ item.label }}
          </SelectItem>
        </SelectGroup>
      </SelectContent>
    </Select>
  </ButtonGroup>
</template>

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/c-button-group-33.json

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

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