diff --git a/src/components/InitialSetup.ts b/src/components/InitialSetup.ts index cfbf157..21ce894 100644 --- a/src/components/InitialSetup.ts +++ b/src/components/InitialSetup.ts @@ -20,6 +20,7 @@ import '@components/LoadingView'; import '@components/ProgressSteps'; import '@components/RelayLogs'; import '@components/Setup/CCNList'; +import '@components/Setup/SeedPhraseSpinner'; import { NDKEvent, NDKKind, NDKPrivateKeySigner, NDKRelay, NDKRelaySet } from '@nostr-dev-kit/ndk'; import { nip19 } from '@nostr/tools'; @@ -300,7 +301,7 @@ export class InitialSetup extends LitElement {

Welcome to Eve

-

Your Private Community Network

+

Your Closed Community Network

Connect, share, and engage with your community in a secure, members-only space designed just for you. @@ -539,21 +540,7 @@ export class InitialSetup extends LitElement { Security) to enable simpler invitation-based community access, as well as improve your community's security.

-
- - this.generateSeedPhrase()} - label="Generate" - variant="secondary" - > - -
+

Community Name

diff --git a/src/components/Setup/SeedPhraseSpinner.ts b/src/components/Setup/SeedPhraseSpinner.ts new file mode 100644 index 0000000..976b682 --- /dev/null +++ b/src/components/Setup/SeedPhraseSpinner.ts @@ -0,0 +1,160 @@ +import { ArxInputChangeEvent } from '@/components/General/Input'; +import * as nip06 from '@nostr/tools/nip06'; +import { wordlist } from '@scure/bip39/wordlists/english'; +import { LitElement, css, html } from 'lit'; +import { customElement, state } from 'lit/decorators.js'; +import { map } from 'lit/directives/map.js'; +import { when } from 'lit/directives/when.js'; + +import '@components/General/Button'; + +@customElement('arx-seed-phrase-spinner') +export class SeedPhraseSpinner extends LitElement { + @state() + private words: (string | null)[] = [null, null, null, null, null, null, null, null, null, null, null, null]; + + @state() + private animating = false; + + @state() + private tempWords: (string | null)[] = [null, null, null, null, null, null, null, null, null, null, null, null]; + + private getRandomWord() { + return wordlist[Math.floor(Math.random() * wordlist.length)]; + } + + static override styles = css` + .words-list { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 0.8rem; + width: 100%; + margin-bottom: 1rem; + } + + .word { + width: 100%; + height: 3.5rem; + overflow: hidden; + position: relative; + border-radius: 0.5rem; + background: rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1); + } + + .word::before, .word::after { + content: ''; + position: absolute; + left: 0; + right: 0; + height: 0.5rem; + z-index: 1; + pointer-events: none; + } + + .word::before { + top: 0; + background: linear-gradient(to bottom, rgba(255, 255, 255, 0.7), transparent); + } + + .word::after { + bottom: 0; + background: linear-gradient(to top, rgba(255, 255, 255, 0.7), transparent); + } + + .word-inner { + display: flex; + flex-direction: column; + position: absolute; + width: 100%; + transition: transform 0.8s cubic-bezier(0.4, 0, 0.2, 1); + will-change: transform; + } + + .word-item { + height: 3.5rem; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.5rem; + font-weight: bold; + text-align: center; + padding: 0 0.25rem; + } + + .controls { + display: flex; + justify-content: center; + margin-top: 1rem; + } + + @keyframes spin { + 0% { transform: translateY(0); } + 100% { transform: translateY(-3.5rem); } + } + + .spinning .word-inner { + animation: spin var(--animation-duration) var(--animation-curve) infinite; + } + + .placeholder { + opacity: 0.5; + } + `; + + override render() { + return html` +
+ ${map( + this.tempWords, + (word) => + html` +
+
+ ${when( + this.animating, + () => html` +
${word}
+
${word}
+ `, + () => + html` +
${word || 'tap generate'}
+ `, + )} +
+
+ `, + )} +
+
+ +
+ `; + } + + private generateSeedPhrase() { + if (this.animating) return; + + this.animating = true; + + const intervalId = window.setInterval(() => { + this.tempWords = this.tempWords.map(() => this.getRandomWord()); + }, 50); + + setTimeout(() => { + const newWords = nip06.generateSeedWords().split(' '); + clearInterval(intervalId); + this.tempWords = newWords; + this.words = newWords; + this.animating = false; + this.dispatchEvent(new ArxInputChangeEvent(this.words.join(' '))); + }, 1500); + } +}