@octabits-io/nuxt-ui-kit 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,67 @@
1
+ <script setup lang="ts">
2
+ // Shipped as source: the consumer's Vite compiles this SFC. All imports are
3
+ // explicit — no reliance on the consumer's auto-import configuration.
4
+ // i18n key contract: ai.review.title / description / currentValue / apply / dismiss.
5
+ import { useI18n } from 'vue-i18n'
6
+ import UCard from '@nuxt/ui/components/Card.vue'
7
+ import UIcon from '@nuxt/ui/components/Icon.vue'
8
+ import UButton from '@nuxt/ui/components/Button.vue'
9
+
10
+ const { t } = useI18n()
11
+
12
+ export interface AiResultField {
13
+ label: string
14
+ value: string
15
+ currentValue?: string | null
16
+ }
17
+
18
+ defineProps<{
19
+ fields: AiResultField[]
20
+ }>()
21
+
22
+ const emit = defineEmits<{
23
+ apply: []
24
+ dismiss: []
25
+ }>()
26
+ </script>
27
+
28
+ <template>
29
+ <UCard class="mb-4">
30
+ <template #header>
31
+ <div class="flex items-center">
32
+ <UIcon name="i-lucide-sparkles" class="mr-2 size-4 text-primary" />
33
+ <span class="font-medium">{{ t('ai.review.title') }}</span>
34
+ </div>
35
+ </template>
36
+
37
+ <p class="mb-3 text-sm text-muted">
38
+ {{ t('ai.review.description') }}
39
+ </p>
40
+
41
+ <div v-for="(field, index) in fields" :key="index" class="mb-4 last:mb-0">
42
+ <div class="mb-1 text-xs font-medium text-muted">{{ field.label }}</div>
43
+ <div class="rounded-md bg-elevated p-3 text-sm">
44
+ {{ field.value }}
45
+ </div>
46
+ <div v-if="field.currentValue" class="mt-1 text-xs text-muted">
47
+ {{ t('ai.review.currentValue') }}: {{ field.currentValue }}
48
+ </div>
49
+ </div>
50
+
51
+ <template #footer>
52
+ <div class="flex justify-end gap-2">
53
+ <UButton
54
+ :label="t('ai.review.dismiss')"
55
+ variant="ghost"
56
+ color="neutral"
57
+ @click="emit('dismiss')"
58
+ />
59
+ <UButton
60
+ :label="t('ai.review.apply')"
61
+ color="primary"
62
+ @click="emit('apply')"
63
+ />
64
+ </div>
65
+ </template>
66
+ </UCard>
67
+ </template>
@@ -0,0 +1,60 @@
1
+ <script setup lang="ts">
2
+ // Shipped as source: the consumer's Vite compiles this SFC. All imports are
3
+ // explicit — no reliance on the consumer's auto-import configuration. The
4
+ // composable comes from the package root (self-reference) so its singleton
5
+ // dialog state is shared with feature code calling useConfirm().
6
+ import { computed } from 'vue'
7
+ import { useI18n } from 'vue-i18n'
8
+ import UModal from '@nuxt/ui/components/Modal.vue'
9
+ import UButton from '@nuxt/ui/components/Button.vue'
10
+ import { useConfirmState } from '@octabits-io/nuxt-ui-kit'
11
+
12
+ const props = defineProps<{
13
+ /**
14
+ * Tailwind z-index class applied to overlay + content (e.g. `z-[100]`) so
15
+ * the dialog stacks above slideovers/modals that triggered it.
16
+ */
17
+ zIndexClass?: string
18
+ /** i18n key for the cancel button default. */
19
+ cancelTextKey?: string
20
+ /** i18n key for the confirm button default. */
21
+ confirmTextKey?: string
22
+ }>()
23
+
24
+ const { isOpen, options, handleConfirm, handleCancel } = useConfirmState()
25
+ const { t } = useI18n()
26
+
27
+ const ui = computed(() =>
28
+ props.zIndexClass ? { overlay: props.zIndexClass, content: props.zIndexClass } : undefined,
29
+ )
30
+ </script>
31
+
32
+ <template>
33
+ <UModal v-model:open="isOpen" :ui="ui">
34
+ <template #header>
35
+ <h3 class="text-lg font-semibold">{{ options.title }}</h3>
36
+ </template>
37
+
38
+ <template #body>
39
+ <p v-if="options.message" class="text-sm text-muted">
40
+ {{ options.message }}
41
+ </p>
42
+ </template>
43
+
44
+ <template #footer>
45
+ <div class="flex justify-end gap-2">
46
+ <UButton
47
+ :label="options.cancelText ?? t(props.cancelTextKey ?? 'common.cancel')"
48
+ color="neutral"
49
+ variant="outline"
50
+ @click="handleCancel"
51
+ />
52
+ <UButton
53
+ :label="options.confirmText ?? t(props.confirmTextKey ?? 'common.confirm')"
54
+ :color="options.dangerous ? 'error' : 'primary'"
55
+ @click="handleConfirm"
56
+ />
57
+ </div>
58
+ </template>
59
+ </UModal>
60
+ </template>
@@ -0,0 +1,66 @@
1
+ <script setup lang="ts">
2
+ // Shipped as source: the consumer's Vite compiles this SFC. All imports are
3
+ // explicit — no reliance on the consumer's auto-import configuration.
4
+ import { computed, ref } from 'vue'
5
+ import { useI18n } from 'vue-i18n'
6
+ import { CalendarDate, parseDate } from '@internationalized/date'
7
+ import UPopover from '@nuxt/ui/components/Popover.vue'
8
+ import UButton from '@nuxt/ui/components/Button.vue'
9
+ import UCalendar from '@nuxt/ui/components/Calendar.vue'
10
+
11
+ /**
12
+ * Single-date input built on the Nuxt UI 4 date primitives (`UPopover` +
13
+ * `UCalendar`). The model is an ISO `YYYY-MM-DD` string so it drops into Zod
14
+ * schemas and API payloads without conversion. Use this instead of a raw
15
+ * `<UInput type="date">`.
16
+ */
17
+ const props = withDefaults(defineProps<{
18
+ modelValue: string
19
+ placeholder?: string
20
+ disabled?: boolean
21
+ }>(), { placeholder: undefined, disabled: false })
22
+
23
+ const emit = defineEmits<{ 'update:modelValue': [value: string] }>()
24
+
25
+ const { locale } = useI18n()
26
+ const open = ref(false)
27
+
28
+ const calendarValue = computed<CalendarDate | undefined>({
29
+ get() {
30
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(props.modelValue)) return undefined
31
+ try {
32
+ return parseDate(props.modelValue)
33
+ } catch {
34
+ return undefined
35
+ }
36
+ },
37
+ set(val) {
38
+ emit('update:modelValue', val ? val.toString() : '')
39
+ open.value = false
40
+ },
41
+ })
42
+
43
+ const label = computed(() => {
44
+ const v = calendarValue.value
45
+ if (!v) return ''
46
+ return new Date(v.year, v.month - 1, v.day).toLocaleDateString(locale.value)
47
+ })
48
+ </script>
49
+
50
+ <template>
51
+ <UPopover v-model:open="open">
52
+ <UButton
53
+ variant="outline"
54
+ color="neutral"
55
+ icon="i-lucide-calendar"
56
+ class="w-full justify-start font-normal"
57
+ :class="{ 'text-dimmed': !calendarValue }"
58
+ :disabled="disabled"
59
+ >
60
+ {{ label || placeholder }}
61
+ </UButton>
62
+ <template #content>
63
+ <UCalendar v-model="calendarValue" class="p-2" />
64
+ </template>
65
+ </UPopover>
66
+ </template>