neptune-web-wallet/src/views/Auth/components/SeedPhraseDisplayComponent.vue

297 lines
8.5 KiB
Vue
Raw Normal View History

2025-10-22 00:16:32 +07:00
<script setup lang="ts">
2025-10-24 22:49:46 +07:00
import { defineEmits, computed } from 'vue'
2025-10-22 00:16:32 +07:00
import { ButtonCommon } from '@/components'
2025-10-24 22:49:46 +07:00
import { useNeptuneStore } from '@/stores/neptuneStore'
import { message } from 'ant-design-vue'
2025-10-22 00:16:32 +07:00
const emit = defineEmits<{
next: []
back: []
}>()
2025-10-24 22:49:46 +07:00
const neptuneStore = useNeptuneStore()
2025-10-22 00:16:32 +07:00
2025-10-24 22:49:46 +07:00
const seedWords = computed(() => neptuneStore.getSeedPhrase || [])
2025-10-22 00:16:32 +07:00
const handleNext = () => {
2025-10-24 22:49:46 +07:00
if (!seedWords.value || seedWords.value.length === 0) {
message.error('❌ Cannot proceed without seed phrase')
return
}
2025-10-22 00:16:32 +07:00
emit('next')
}
const handleBack = () => {
emit('back')
}
2025-10-24 22:49:46 +07:00
const handleCopySeed = async () => {
if (!seedWords.value || seedWords.value.length === 0) {
message.error('No seed phrase to copy')
return
}
try {
const seedPhrase = seedWords.value.join(' ')
await navigator.clipboard.writeText(seedPhrase)
message.success('Seed phrase copied to clipboard!')
} catch (err) {
message.error('Failed to copy seed phrase')
}
}
2025-10-22 00:16:32 +07:00
</script>
<template>
<div class="recovery-container">
<div class="recovery-card">
<div class="recovery-header">
<h1 class="recovery-title">Recovery Seed</h1>
</div>
<div class="recovery-content">
<div class="instruction-text">
<p>
Your wallet is accessible by a seed phrase. The seed phrase is an ordered
2025-10-24 22:49:46 +07:00
18-word secret phrase.
2025-10-22 00:16:32 +07:00
</p>
<p>
Make sure no one is looking, as anyone with your seed phrase can access your
2025-10-24 22:49:46 +07:00
wallet and funds. Write it down and keep it safe.
2025-10-22 00:16:32 +07:00
</p>
</div>
2025-10-24 22:49:46 +07:00
<div v-if="seedWords.length > 0" class="seed-words-container">
2025-10-22 00:16:32 +07:00
<div class="seed-words-grid">
<div v-for="(word, index) in seedWords" :key="index" class="seed-word-item">
<span class="word-number">{{ index + 1 }}</span>
<span class="word-text">{{ word }}</span>
</div>
</div>
2025-10-24 22:49:46 +07:00
<button class="copy-seed-btn" @click="handleCopySeed" type="button">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
></path>
</svg>
Copy Seed Phrase
</button>
2025-10-22 00:16:32 +07:00
</div>
2025-10-24 22:49:46 +07:00
<div v-else class="no-seed-warning">
<p> No seed phrase found. Please go back and generate a wallet first.</p>
2025-10-23 18:36:58 +07:00
</div>
2025-10-22 00:16:32 +07:00
<div class="cool-fact">
<p>
2025-10-24 22:49:46 +07:00
Cool fact: there are more 18-word phrase combinations than atoms in the
observable universe!
2025-10-22 00:16:32 +07:00
</p>
</div>
<div class="recovery-actions">
<ButtonCommon type="default" size="large" @click="handleBack">
BACK
</ButtonCommon>
2025-10-24 22:49:46 +07:00
<ButtonCommon
type="primary"
size="large"
@click="handleNext"
:disabled="!seedWords || seedWords.length === 0"
>
2025-10-22 00:16:32 +07:00
NEXT
</ButtonCommon>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.recovery-container {
display: flex;
align-items: center;
justify-content: center;
padding: var(--spacing-xl);
background: var(--bg-light);
min-height: 100vh;
}
.recovery-card {
@include card-base;
max-width: 500px;
width: 100%;
border: 2px solid var(--primary-color);
}
.recovery-header {
text-align: center;
margin-bottom: var(--spacing-2xl);
padding-bottom: var(--spacing-xl);
border-bottom: 1px solid var(--border-color);
.recovery-title {
font-size: var(--font-2xl);
font-weight: var(--font-bold);
color: var(--text-primary);
margin: 0;
}
}
.recovery-content {
.instruction-text {
margin-bottom: var(--spacing-2xl);
p {
font-size: var(--font-sm);
color: var(--text-secondary);
line-height: var(--leading-normal);
margin-bottom: var(--spacing-md);
&:last-child {
margin-bottom: 0;
}
}
}
.seed-words-container {
margin-bottom: var(--spacing-2xl);
padding: var(--spacing-lg);
background: var(--bg-hover);
border-radius: var(--radius-md);
border: 1px solid var(--border-light);
.seed-words-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: var(--spacing-md);
2025-10-24 22:49:46 +07:00
margin-bottom: var(--spacing-md);
2025-10-22 00:16:32 +07:00
.seed-word-item {
display: flex;
align-items: center;
gap: var(--spacing-sm);
padding: var(--spacing-sm);
background: var(--bg-white);
border-radius: var(--radius-sm);
border: 1px solid var(--border-light);
.word-number {
font-size: var(--font-xs);
font-weight: var(--font-bold);
color: var(--text-muted);
min-width: 20px;
}
.word-text {
font-size: var(--font-sm);
font-weight: var(--font-medium);
color: var(--text-primary);
}
}
}
2025-10-24 22:49:46 +07:00
.copy-seed-btn {
display: flex;
align-items: center;
gap: var(--spacing-sm);
width: 100%;
padding: var(--spacing-sm) var(--spacing-md);
background: var(--primary-color);
color: var(--text-light);
border: none;
border-radius: var(--radius-sm);
font-size: var(--font-sm);
font-weight: var(--font-medium);
cursor: pointer;
transition: all 0.2s ease;
justify-content: center;
svg {
flex-shrink: 0;
}
&:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 127, 207, 0.3);
}
&:active {
transform: translateY(0);
}
}
2025-10-22 00:16:32 +07:00
}
.cool-fact {
margin-bottom: var(--spacing-2xl);
text-align: center;
p {
font-size: var(--font-xs);
color: var(--text-muted);
font-style: italic;
margin: 0;
}
}
.recovery-actions {
display: flex;
justify-content: space-between;
gap: var(--spacing-md);
}
2025-10-24 22:49:46 +07:00
.no-seed-warning {
padding: var(--spacing-xl);
background: var(--error-light);
border: 2px solid var(--error-color);
border-radius: var(--radius-md);
text-align: center;
margin-bottom: var(--spacing-2xl);
p {
font-size: var(--font-md);
color: var(--error-color);
font-weight: var(--font-bold);
margin: 0;
}
2025-10-23 18:36:58 +07:00
}
}
2025-10-24 22:49:46 +07:00
@include screen(mobile) {
2025-10-22 00:16:32 +07:00
.recovery-container {
padding: var(--spacing-md);
}
.recovery-card {
max-width: 100%;
}
2025-10-24 22:49:46 +07:00
.recovery-content {
.seed-words-container {
.seed-words-grid {
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-sm);
2025-10-22 00:16:32 +07:00
2025-10-24 22:49:46 +07:00
.seed-word-item {
padding: var(--spacing-xs);
2025-10-22 00:16:32 +07:00
2025-10-24 22:49:46 +07:00
.word-number {
min-width: 16px;
}
2025-10-22 00:16:32 +07:00
}
}
}
}
}
</style>