118 lines
3.2 KiB
Vue
118 lines
3.2 KiB
Vue
<script setup lang="ts">
|
|
import { t } from '@/i18n'
|
|
|
|
import { computed, nextTick, ref, watch } from 'vue'
|
|
import { useCopyToClipboard } from '@/composables/useCopyToClipboard'
|
|
|
|
const props = defineProps<{
|
|
name: string
|
|
apiKey: string
|
|
}>()
|
|
|
|
const open = defineModel<boolean>('open', { default: false })
|
|
|
|
const emit = defineEmits<{ done: [] }>()
|
|
|
|
const { copied, copy } = useCopyToClipboard()
|
|
const copyButton = ref<{ $el: HTMLElement } | null>(null)
|
|
|
|
const description = computed(() =>
|
|
t('"{0}" is ready. Copy the key and store it somewhere safe.', [props.name]),
|
|
)
|
|
const copyLabel = computed(() => (copied.value ? t('Copied') : t('Copy')))
|
|
const copyIcon = computed(() => (copied.value ? 'i-lucide-check' : 'i-lucide-copy'))
|
|
|
|
watch(
|
|
open,
|
|
async (isOpen) => {
|
|
if (!isOpen) {
|
|
return
|
|
}
|
|
await nextTick()
|
|
await nextTick()
|
|
copyButton.value?.$el?.focus()
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
function onOpenChange(isOpen: boolean) {
|
|
if (!isOpen) {
|
|
emit('done')
|
|
}
|
|
}
|
|
|
|
function keepOpenOnOutsideInteraction(event: Event) {
|
|
event.preventDefault()
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<UModal
|
|
:open="open"
|
|
:title="t('Your new API key')"
|
|
:description="description"
|
|
:close="false"
|
|
:content="{
|
|
onPointerDownOutside: keepOpenOnOutsideInteraction,
|
|
onInteractOutside: keepOpenOnOutsideInteraction,
|
|
}"
|
|
:ui="{
|
|
content:
|
|
'divide-y-0 border border-default shadow-(--shadow-modal) ring-0 sm:top-30 sm:max-w-120 sm:translate-y-0 max-sm:!inset-x-4 max-sm:!top-auto max-sm:!bottom-4 max-sm:!left-4 max-sm:!w-auto max-sm:!max-w-none max-sm:!translate-x-0 max-sm:!translate-y-0',
|
|
header: 'min-h-0 px-5 pt-5 pb-0 sm:px-5',
|
|
title: 'text-[1.125rem]/6.5 font-semibold',
|
|
description: 'mt-1 text-base/5.5 text-toned text-pretty',
|
|
body: 'px-5 pt-3.5 pb-0 sm:px-5 sm:pt-3.5 sm:pb-0',
|
|
footer: 'px-5 pt-3.5 pb-5 sm:px-5',
|
|
}"
|
|
@update:open="onOpenChange"
|
|
>
|
|
<template #body>
|
|
<div class="flex flex-col gap-3.5">
|
|
<UAlert
|
|
role="alert"
|
|
color="warning"
|
|
variant="soft"
|
|
:close="false"
|
|
icon="i-lucide-triangle-alert"
|
|
:title="t('You won\'t be able to see this key again.')"
|
|
:ui="{ root: 'gap-2.5 px-3 py-2.5', title: 'text-sm font-medium' }"
|
|
/>
|
|
<div class="flex flex-col border border-accented bg-elevated md:flex-row">
|
|
<span
|
|
class="min-w-0 flex-1 px-3 py-2.5 font-mono text-code/5 break-all text-highlighted"
|
|
>{{ apiKey }}</span
|
|
>
|
|
<UButton
|
|
ref="copyButton"
|
|
:icon="copyIcon"
|
|
color="neutral"
|
|
variant="ghost"
|
|
aria-live="polite"
|
|
class="h-11 justify-center gap-1.5 rounded-none border-t border-accented px-3.5 font-medium md:border-t-0 md:border-l"
|
|
:class="copied ? 'text-success' : 'text-highlighted'"
|
|
:ui="{ leadingIcon: 'size-3.5' }"
|
|
@click="copy(apiKey)"
|
|
>
|
|
{{ copyLabel }}
|
|
</UButton>
|
|
</div>
|
|
<span class="text-muted">{{
|
|
t('Closing this window discards the key from the screen. Copy it first.')
|
|
}}</span>
|
|
</div>
|
|
</template>
|
|
<template #footer>
|
|
<div class="flex w-full flex-col sm:flex-row sm:justify-end">
|
|
<UButton
|
|
block
|
|
class="h-11 justify-center sm:w-auto sm:px-3.5"
|
|
@click="emit('done')"
|
|
>
|
|
{{ t('Done') }}
|
|
</UButton>
|
|
</div>
|
|
</template>
|
|
</UModal>
|
|
</template>
|