main
vue 59 lines 1.54 KB
Raw
1 <template>
2 <div class="flex flex-col gap-2">
3 <n-alert type="info">Backup codes generated. Save them — they are shown only once.</n-alert>
4
5 <div class="grid max-w-140 grid-cols-2 gap-2">
6 <n-code v-for="code in codes" :key="code" class="p-2 text-center">
7 {{ code }}
8 </n-code>
9 </div>
10
11 <div class="flex gap-2">
12 <n-button v-if="isCopySupported" size="small" secondary @click="copyBackupCodes(codes)">
13 <template #icon>
14 <Icon name="carbon:copy" />
15 </template>
16 Copy all
17 </n-button>
18 <n-button size="small" secondary @click="downloadBackupCodes(codes)">
19 <template #icon>
20 <Icon name="carbon:download" />
21 </template>
22 Download .txt
23 </n-button>
24 </div>
25 </div>
26 </template>
27
28 <script lang="ts" setup>
29 import { useClipboard } from "@vueuse/core"
30 import { saveAs } from "file-saver"
31 import { NAlert, NButton, NCode, useMessage } from "naive-ui"
32 import { watch } from "vue"
33 import Icon from "@/components/common/Icon.vue"
34
35 defineProps<{
36 codes: string[]
37 }>()
38
39 const message = useMessage()
40 const { copy, copied, isSupported: isCopySupported } = useClipboard()
41
42 function copyBackupCodes(codes: string[]) {
43 copy(codes.join("\n"))
44 }
45
46 function downloadBackupCodes(codes: string[]) {
47 const text = `CoPilot — 2FA Backup Codes\n${"=".repeat(30)}\n\n${codes.join(
48 "\n"
49 )}\n\nKeep these codes safe. Each code can only be used once.\n`
50
51 saveAs(new Blob([text], { type: "text/plain" }), "copilot-2fa-backup-codes.txt")
52 }
53
54 watch(copied, newVal => {
55 if (newVal) {
56 message.success("Backup codes copied to clipboard")
57 }
58 })
59 </script>