Improve initial setup screen:

📊 Add relay log visibility during startup
💼 Implement automatic wallet configuration
🧭 Add progress indicator showing current setup step
🧹 Fix minor linting issues throughout codebase
This commit is contained in:
Danny Morabito 2025-04-02 11:51:45 +02:00
parent 295137b313
commit 9fe777abd9
Signed by: dannym
GPG key ID: 7CC8056A5A04557E
7 changed files with 217 additions and 72 deletions

View file

@ -211,6 +211,7 @@ export class StyledButton extends LitElement {
composed: true,
}),
);
return;
}
private _handleKeyDown(e: KeyboardEvent) {

View file

@ -10,11 +10,13 @@ import * as nostrTools from '@nostr/tools/pure';
import { encodeBase64 } from '@std/encoding/base64';
import { LitElement, css, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js';
import '@components/General/Button';
import '@components/General/Fieldset';
import '@components/General/Input';
import '@components/LoadingView';
import '@components/ProgressSteps';
@customElement('arx-initial-setup')
export class InitialSetup extends LitElement {
@ -24,6 +26,13 @@ export class InitialSetup extends LitElement {
@state() private userName = '';
@state() private profileImage = '';
@state() private lightningAddress = '';
@state() private relayStatus: { running: boolean; pid: number | null; logs: string[] } = {
running: false,
pid: null,
logs: [],
};
private readonly pageLabels = ['Welcome', 'Seed Phrase', 'Relay Setup', 'Profile', 'Complete'];
get encryptionPassphrase() {
let encryptionPassphrase = localStorage.getItem('encryption_key');
@ -85,6 +94,7 @@ export class InitialSetup extends LitElement {
oklch(from var(--color-accent) l calc(c * 1.2) h)
);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
margin-bottom: calc(var(--spacing-unit) * 8);
}
@ -139,7 +149,6 @@ export class InitialSetup extends LitElement {
}
pre {
white-space: normal;
background-color: var(--color-base-200);
padding: calc(var(--spacing-unit) * 4);
border-radius: var(--radius-field);
@ -220,6 +229,10 @@ export class InitialSetup extends LitElement {
private renderPageOne() {
return html`
<main class="welcome-container" ${animate()}>
<arx-progress-steps
.currentPage=${this.currentPage}
.pageLabels=${this.pageLabels}
></arx-progress-steps>
<section>
<h1>Welcome to Eve</h1>
<h2>Your Private Community Network</h2>
@ -270,6 +283,10 @@ export class InitialSetup extends LitElement {
private renderPageTwo() {
return html`
<main class="welcome-container" ${animate()}>
<arx-progress-steps
.currentPage=${this.currentPage}
.pageLabels=${this.pageLabels}
></arx-progress-steps>
<section>
<h1>Getting Started</h1>
<h2>Creating a Community</h2>
@ -338,11 +355,21 @@ export class InitialSetup extends LitElement {
private async startRelay() {
await window.relay.writeSeed(this.seedPhrase);
await window.relay.start(this.encryptionPassphrase);
this.updateRelayStatus();
}
private async updateRelayStatus() {
this.relayStatus = await window.relay.getStatus();
if (this.relayStatus.running) setTimeout(() => this.updateRelayStatus(), 2000);
}
private renderPageThree() {
return html`
<main class="welcome-container" ${animate()}>
<arx-progress-steps
.currentPage=${this.currentPage}
.pageLabels=${this.pageLabels}
></arx-progress-steps>
<section>
<h2>Configure Eve Relay</h2>
<p>
@ -352,11 +379,25 @@ export class InitialSetup extends LitElement {
<p>Please press the button below to start the relay.</p>
<arx-button
variant="primary"
label="Start Relay"
label=${this.relayStatus.running ? 'Relay Running' : 'Start Relay'}
?disabled=${this.relayStatus.running}
@click=${() => this.startRelay()}
>
Start Relay
${when(
this.relayStatus.running,
() => html`<iconify-icon slot="prefix" icon="mdi:check-circle"></iconify-icon>`,
)}
</arx-button>
${when(
this.relayStatus.running,
() => html`
<p class="note">
<iconify-icon icon="mdi:information"></iconify-icon>
Relay is running with PID: ${this.relayStatus.pid}
</p>
<pre class="relay-logs">${this.relayStatus.logs.slice(-5).join('\n')}</pre>
`,
)}
<p>
Having trouble? Our team is here to help if you encounter any
issues.
@ -374,6 +415,7 @@ export class InitialSetup extends LitElement {
<arx-button
@click=${() => this.handleNavigation(4)}
variant="primary"
?disabled=${!this.relayStatus.running}
label="Continue"
>
</arx-button>
@ -390,13 +432,13 @@ export class InitialSetup extends LitElement {
this.profileImage = e.detail.value;
}
private onLightningAddressInput(e: CustomEvent<{ value: string }>) {
this.lightningAddress = e.detail.value;
}
private renderPageFour() {
return html`
<main class="welcome-container" ${animate()}>
<arx-progress-steps
.currentPage=${this.currentPage}
.pageLabels=${this.pageLabels}
></arx-progress-steps>
<section>
<h2>Complete Your Profile</h2>
<p>Great progress! Let's set up your community profile.</p>
@ -437,9 +479,9 @@ export class InitialSetup extends LitElement {
>
</arx-button>
<arx-button
@click=${() => this.handleNavigation(5)}
@click=${() => this.goToFinalStep()}
variant="primary"
label="Final Step"
label="Next"
>
</arx-button>
</div>
@ -447,53 +489,12 @@ export class InitialSetup extends LitElement {
`;
}
private renderPageFive() {
return html`
<main class="welcome-container" ${animate()}>
<section>
<h2>Payment Setup</h2>
<p>Almost done! Let's set up your payment options.</p>
<p>
Enter your existing Lightning address below for payments within the
community. If you don't have one, leave this field blank and we'll
automatically generate one for you through
<a target="_blank" href="https://npub.cash" class="external-link"
>npub.cash</a
>.
</p>
<arx-input
id="lightning-address"
type="text"
.value=${this.lightningAddress}
@change=${this.onLightningAddressInput}
placeholder="your@lightning.address"
/></arx-input>
<small class="note">
Your Lightning address enables secure, instant payments within the
community.
</small>
</section>
<div class="navigation">
<arx-button
@click=${() => this.handleNavigation(4)}
variant="secondary"
label="Back"
>
</arx-button>
<arx-button variant="primary" label="Next" @click=${() => this.goToFinalStep()}>
</arx-button>
</div>
</main>
`;
}
private async goToFinalStep() {
const randomPrivateKey = nostrTools.generateSecretKey();
const encryptedNsec = nip49.encrypt(randomPrivateKey, this.encryptionPassphrase);
const npub = nip19.npubEncode(nostrTools.getPublicKey(randomPrivateKey));
if (!this.lightningAddress) this.lightningAddress = `${npub}@npub.cash`;
this.lightningAddress = `${npub}@npub.cash`;
localStorage.setItem('ncryptsec', encryptedNsec);
@ -510,12 +511,16 @@ export class InitialSetup extends LitElement {
await event.sign();
await event.publish();
this.handleNavigation(6);
this.handleNavigation(5);
}
private renderPageSix() {
private renderPageFive() {
return html`
<main class="welcome-container" ${animate()}>
<arx-progress-steps
.currentPage=${this.currentPage}
.pageLabels=${this.pageLabels}
></arx-progress-steps>
<section>
<h2>Done!</h2>
<p>
@ -528,19 +533,13 @@ export class InitialSetup extends LitElement {
required to invite new members to the community.
</p>
<p>Your username is: <b>${this.userName}</b></p>
${
this.profileImage
? html` <p>
Your profile image is: <img .src=${this.profileImage} />
</p>`
: ''
}
${when(this.profileImage, () => html`<p>Your profile image is: <img .src=${this.profileImage} /></p>`)}
<p>Your lightning address is: <b>${this.lightningAddress}</b></p>
</section>
<div class="navigation">
<arx-button
@click=${() => this.handleNavigation(5)}
@click=${() => this.handleNavigation(4)}
variant="secondary"
label="Back"
>
@ -581,8 +580,6 @@ export class InitialSetup extends LitElement {
return this.renderPageFour();
case 5:
return this.renderPageFive();
case 6:
return this.renderPageSix();
default:
return html`<div class="welcome-container">
<arx-loading-view></arx-loading-view>

View file

@ -0,0 +1,114 @@
import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@customElement('arx-progress-steps')
export class ProgressSteps extends LitElement {
@property({ type: Number }) currentPage = 1;
@property({ type: Array }) pageLabels: string[] = [];
static override styles = css`
:host {
display: block;
width: 100%;
margin-bottom: calc(var(--spacing-unit) * 8);
}
.progress-container {
display: flex;
flex-direction: column;
gap: calc(var(--spacing-unit) * 2);
}
.progress-bar {
width: 100%;
height: 4px;
background: var(--color-base-200);
border-radius: 2px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: var(--color-accent);
transition: width 0.3s ease;
}
.page-indicators {
display: flex;
justify-content: space-between;
padding: 0 calc(var(--spacing-unit) * 2);
}
.page-indicator {
display: flex;
flex-direction: column;
align-items: center;
gap: calc(var(--spacing-unit) * 1);
}
.page-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--color-base-300);
transition: all 0.3s ease;
}
.page-dot.active {
background: var(--color-accent);
transform: scale(1.2);
}
.page-dot.completed {
background: var(--color-accent);
}
.page-label {
font-size: 0.875rem;
color: var(--color-secondary);
transition: color 0.3s ease;
}
.page-label.active {
color: var(--color-accent);
font-weight: 500;
}
.page-label.completed {
color: var(--color-accent);
}
`;
override render() {
const progress = ((this.currentPage - 1) / (this.pageLabels.length - 1)) * 100;
return html`
<div class="progress-container">
<div class="progress-bar">
<div
class="progress-fill"
style="width: ${progress}%"
></div>
</div>
<div class="page-indicators">
${this.pageLabels.map((label, index) => {
const pageNum = index + 1;
const isActive = pageNum === this.currentPage;
const isCompleted = pageNum < this.currentPage;
return html`
<div class="page-indicator">
<div
class="page-dot ${isActive ? 'active' : ''} ${isCompleted ? 'completed' : ''}"
></div>
<span
class="page-label ${isActive ? 'active' : ''} ${isCompleted ? 'completed' : ''}"
>${label}</span>
</div>
`;
})}
</div>
</div>
`;
}
}