date-selector

Date selector with dropdown menu

Date selector with dropdown menu

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

src/date-selector/c-date-selector-4.vue

<!--
  IconPlaceholder (иконки "calendar" в триггере диалога, "chevron-down" в
  триггере переключателя языка) заменена инлайновым `<svg>`. Оба плавающих
  слоя (Dialog, DropdownMenu) закрыты по умолчанию — их содержимое (включая
  `DateSelector`) не монтируется, известное расхождение сетки календаря
  сюда не попадает.
-->
<script setup lang="ts">
import { computed, ref, watch } from "vue"
import { DateSelector, DEFAULT_DATE_SELECTOR_I18N } from "@/components/reui/date-selector"
import { Button } from "@/components/ui/button"
import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { DateSelectorValue } from "@/components/reui/date-selector"

const languageMetadata = {
  en: { label: "English", flag: "🇺🇸", dateFormat: "MM/dd/yyyy", weekStartsOn: 0 as const, ui: { label: "Due date", hint: "Try: 2025, Q4, 05/10/2025", placeholder: "Select a date" } },
  es: { label: "Español", flag: "🇪🇸", dateFormat: "dd/MM/yyyy", weekStartsOn: 1 as const, ui: { label: "Fecha de vencimiento", hint: "Prueba: 2025, T4, 05/10/2025", placeholder: "Seleccionar una fecha" } },
  fr: { label: "Français", flag: "🇫🇷", dateFormat: "dd/MM/yyyy", weekStartsOn: 1 as const, ui: { label: "Date d'échéance", hint: "Essayez: 2025, T4, 05/10/2025", placeholder: "Sélectionner une date" } },
  de: { label: "Deutsch", flag: "🇩🇪", dateFormat: "dd.MM.yyyy", weekStartsOn: 1 as const, ui: { label: "Fälligkeitsdatum", hint: "Versuchen Sie: 2025, Q4, 05.10.2025", placeholder: "Datum auswählen" } },
}

const languageOptions = Object.entries(languageMetadata).map(([value, meta]) => ({
  value,
  label: meta.label,
  flag: meta.flag,
}))

const value = ref<DateSelectorValue | undefined>(undefined)
const open = ref(false)
const internalValue = ref<DateSelectorValue | undefined>(value.value)
const currentLanguage = ref<keyof typeof languageMetadata>("fr")

const currentMeta = computed(() => languageMetadata[currentLanguage.value] ?? languageMetadata.en)
const currentI18n = DEFAULT_DATE_SELECTOR_I18N

watch(open, (isOpen) => {
  if (isOpen) {
    internalValue.value = value.value
  }
})

const displayText = computed(() => currentMeta.value.ui.placeholder)
</script>

<template>
  <div class="flex h-full w-full grow flex-col items-stretch gap-4">
    <div class="flex w-full justify-end">
      <DropdownMenu>
        <DropdownMenuTrigger as-child>
          <Button variant="outline" size="sm" class="flex items-center gap-2">
            <span>{{ currentMeta.flag }}</span>
            <span>{{ currentMeta.label }}</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"
            ><path d="m6 9 6 6 6-6" /></svg>
          </Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent align="start">
          <DropdownMenuItem
            v-for="lang in languageOptions"
            :key="lang.value"
            class="flex items-center gap-2"
            @click="currentLanguage = lang.value as keyof typeof languageMetadata"
          >
            <span>{{ lang.flag }}</span>
            <span>{{ lang.label }}</span>
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
    </div>
    <div class="flex grow items-center justify-center">
      <Dialog v-model:open="open">
        <DialogTrigger as-child>
          <Button variant="outline" class="w-56 justify-start">
            <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"
            ><path d="M8 2v4" /><path d="M16 2v4" /><rect width="18" height="18" x="3" y="4" rx="2" /><path d="M3 10h18" /></svg>
            {{ displayText }}
          </Button>
        </DialogTrigger>
        <DialogContent class="sm:max-w-lg" :show-close-button="false">
          <DialogHeader>
            <DialogTitle>{{ currentMeta.ui.label }}</DialogTitle>
          </DialogHeader>
          <DateSelector
            :value="internalValue"
            @change="internalValue = $event"
            :show-input="true"
            :i18n="currentI18n"
            :day-date-format="currentMeta.dateFormat"
            :week-starts-on="currentMeta.weekStartsOn"
          />
          <DialogFooter>
            <DialogClose as-child>
              <Button variant="outline">{{ currentI18n.cancel }}</Button>
            </DialogClose>
            <Button>{{ currentI18n.apply }}</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  </div>
</template>

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/c-date-selector-4.json

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

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