✨ Enhance app with multi-CCN support and improved UX
Features: ✅ Add support for multiple CCNs 🔍 Implement sidebar hiding functionality 🎨 Revamp navigation system for better flow 🖌️ Replace icons with custom-designed assets and improved naming 🚀 Streamline initial setup process 📝 Refine terminology (e.g., "forum thread" → "topic") 🛠️ Enhance forum usability and interaction
This commit is contained in:
parent
bf3c950da0
commit
9893945f55
34 changed files with 792 additions and 308 deletions
|
@ -60,12 +60,12 @@ export class ArborForumCategory extends LitElement {
|
|||
<div class="category-header">
|
||||
<span>${this.title}</span>
|
||||
<arx-button
|
||||
label="New Topic"
|
||||
href="/arbor/new-topic/${this.id}"
|
||||
label="New Thread"
|
||||
href="/arbor/new-thread/${this.id}"
|
||||
></arx-button>
|
||||
</div>
|
||||
<slot>
|
||||
<div class="empty-state">No topics yet...</div>
|
||||
<div class="empty-state">No threads yet...</div>
|
||||
</slot>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -12,7 +12,7 @@ import '@components/MarkdownContent';
|
|||
@customElement('arx-forum-post')
|
||||
export class ForumPost extends LitElement {
|
||||
@property({ type: String }) override id = '';
|
||||
@property({ type: String }) topicId = '';
|
||||
@property({ type: String }) threadId = '';
|
||||
@property({ type: String }) npub = '';
|
||||
@property({ type: Date }) date = new Date();
|
||||
@property({ type: String }) content = '';
|
||||
|
@ -217,12 +217,12 @@ export class ForumPost extends LitElement {
|
|||
}
|
||||
|
||||
private _copyPermalink() {
|
||||
const permalink = `eve://phora/topics/${this.topicId}#post-${this.id}`;
|
||||
const permalink = `eve://phora/threads/${this.threadId}#post-${this.id}`;
|
||||
navigator.clipboard.writeText(permalink);
|
||||
}
|
||||
|
||||
override render() {
|
||||
const permalink = `eve://phora/topics/${this.topicId}#post-${this.id}`;
|
||||
const permalink = `eve://phora/threads/${this.threadId}#post-${this.id}`;
|
||||
|
||||
const postClasses = {
|
||||
post: true,
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import '@components/EveLink';
|
||||
import formatDateTime from '@/utils/formatDateTime';
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement('arx-arbor-forum-topic')
|
||||
export class ArborForumTopic extends LitElement {
|
||||
@customElement('arx-arbor-forum-thread')
|
||||
export class ArborForumThread extends LitElement {
|
||||
static override styles = [
|
||||
css`
|
||||
.topic {
|
||||
.thread {
|
||||
display: grid;
|
||||
grid-template-columns: 3fr 1fr;
|
||||
padding: 1.75rem;
|
||||
|
@ -25,7 +25,7 @@ export class ArborForumTopic extends LitElement {
|
|||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.topic:hover {
|
||||
.thread:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: calc(var(--depth) * 4px) calc(var(--depth) * 4px)
|
||||
calc(var(--depth) * 8px)
|
||||
|
@ -35,7 +35,7 @@ export class ArborForumTopic extends LitElement {
|
|||
oklch(from var(--color-base-100) l c h / 0.5);
|
||||
}
|
||||
|
||||
.topic-icon {
|
||||
.thread-icon {
|
||||
inline-size: 40px;
|
||||
block-size: 40px;
|
||||
background: var(--color-accent);
|
||||
|
@ -48,7 +48,7 @@ export class ArborForumTopic extends LitElement {
|
|||
oklch(from var(--color-base-content) l c h / 0.15);
|
||||
}
|
||||
|
||||
.topic-icon::after {
|
||||
.thread-icon::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
@ -59,13 +59,13 @@ export class ArborForumTopic extends LitElement {
|
|||
);
|
||||
}
|
||||
|
||||
.topic-info {
|
||||
.thread-info {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.topic-details {
|
||||
.thread-details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ export class ArborForumTopic extends LitElement {
|
|||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.topic-details p {
|
||||
.thread-details p {
|
||||
margin: 0;
|
||||
font-size: 0.975rem;
|
||||
line-height: 1.6;
|
||||
|
@ -156,7 +156,7 @@ export class ArborForumTopic extends LitElement {
|
|||
}
|
||||
|
||||
@media (max-width: 968px) {
|
||||
.topic {
|
||||
.thread {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
padding: 1.25rem;
|
||||
|
@ -188,13 +188,13 @@ export class ArborForumTopic extends LitElement {
|
|||
|
||||
override render() {
|
||||
return html`
|
||||
<div class="topic">
|
||||
<div class="topic-info">
|
||||
<div class="topic-icon"></div>
|
||||
<div class="topic-details">
|
||||
<div class="thread">
|
||||
<div class="thread-info">
|
||||
<div class="thread-icon"></div>
|
||||
<div class="thread-details">
|
||||
<arx-eve-link
|
||||
class="${this.status}"
|
||||
href="/arbor/topics/${this.id}"
|
||||
href="/arbor/threads/${this.id}"
|
||||
>
|
||||
${this.title}
|
||||
</arx-eve-link>
|
|
@ -116,9 +116,12 @@ export class EveDialog extends LitElement {
|
|||
override connectedCallback() {
|
||||
super.connectedCallback();
|
||||
document.addEventListener('keydown', this._handleKeyDown);
|
||||
this.rootWindow = document.body
|
||||
.querySelector('arx-eve-router')!
|
||||
.shadowRoot!.querySelector('.window') as HTMLDivElement;
|
||||
const router = document.querySelector('arx-eve-router');
|
||||
if (router) {
|
||||
this.rootWindow = router.shadowRoot!.querySelector('.window') as HTMLDivElement;
|
||||
} else {
|
||||
this.rootWindow = document.body as HTMLDivElement;
|
||||
}
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
|
@ -168,7 +171,7 @@ export class EveDialog extends LitElement {
|
|||
override render() {
|
||||
return html`
|
||||
<div
|
||||
class="${classMap({ active: this.open })}"
|
||||
class=${classMap({ active: this.open })}
|
||||
@click=${this._handleOverlayClick}
|
||||
style="--dialog-width: ${this.width}; --dialog-max-width: ${this.maxWidth};"
|
||||
>
|
||||
|
|
|
@ -11,7 +11,7 @@ export class StyledSelect<T> extends LitElement {
|
|||
@property() name = '';
|
||||
@property({ type: Boolean }) required = false;
|
||||
@property() label = '';
|
||||
@property({ type: Array<T> }) options = [];
|
||||
@property({ type: Array }) options: T[] = [];
|
||||
@property() valueMapper?: (option: T) => string;
|
||||
@property() textMapper?: (option: T) => string;
|
||||
|
||||
|
@ -106,15 +106,17 @@ export class StyledSelect<T> extends LitElement {
|
|||
private _getOptionValue(option: T) {
|
||||
if (option === undefined || option === null) return '';
|
||||
if (this.valueMapper) return this.valueMapper(option);
|
||||
if (typeof option === 'object' && 'value' in option) return option.value;
|
||||
return option;
|
||||
if (typeof option === 'object' && 'value' in (option as object))
|
||||
return (option as unknown as { value: string }).value;
|
||||
return String(option);
|
||||
}
|
||||
|
||||
private _getOptionText(option: T) {
|
||||
if (option === undefined || option === null) return '';
|
||||
if (this.textMapper) return this.textMapper(option);
|
||||
if (typeof option === 'object' && 'label' in option) return option.label;
|
||||
return option;
|
||||
if (typeof option === 'object' && 'label' in (option as object))
|
||||
return (option as unknown as { label: string }).label;
|
||||
return String(option);
|
||||
}
|
||||
|
||||
override render() {
|
||||
|
@ -144,7 +146,7 @@ export class StyledSelect<T> extends LitElement {
|
|||
const optionText = this._getOptionText(option);
|
||||
return html`
|
||||
<option
|
||||
value=${optionValue}
|
||||
.value=${optionValue}
|
||||
?selected=${optionValue === this.value}
|
||||
>
|
||||
${optionText}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
import { ArxInputChangeEvent } from './Input';
|
||||
|
||||
|
@ -134,7 +135,7 @@ export class StyledTextarea extends LitElement {
|
|||
|
||||
return html`
|
||||
${when(this.label, () => html`<label for="textarea-${this.name}">${this.label}</label>`)}
|
||||
<div class="${hasMaxlength ? 'has-maxlength' : ''}">
|
||||
<div class=${classMap({ 'has-maxlength': hasMaxlength })}>
|
||||
<textarea
|
||||
id="textarea-${this.name}"
|
||||
.value=${this.value}
|
||||
|
@ -142,7 +143,7 @@ export class StyledTextarea extends LitElement {
|
|||
?required=${this.required}
|
||||
placeholder=${this.placeholder}
|
||||
rows=${this.rows}
|
||||
maxlength=${this.maxlength}
|
||||
.maxlength=${Number.parseInt(this.maxlength) || -1}
|
||||
name=${this.name}
|
||||
@input=${this._handleInput}
|
||||
@focus=${this._handleFocus}
|
||||
|
|
|
@ -172,7 +172,7 @@ export class Header extends LitElement {
|
|||
</div>
|
||||
<div class="nav-buttons">
|
||||
<button @click=${this._goToWallet}>
|
||||
<iconify-icon icon="material-symbols:wallet"></iconify-icon>
|
||||
<iconify-icon icon="arx:wallet"></iconify-icon>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
@ -290,11 +290,11 @@ export class Header extends LitElement {
|
|||
window.location.hash = 'arbor';
|
||||
break;
|
||||
case 892:
|
||||
window.location.hash = `arbor/topics/${suggestion.id}`;
|
||||
window.location.hash = `arbor/threads/${suggestion.id}`;
|
||||
break;
|
||||
case 893: {
|
||||
const threadId = suggestion.tags.find((tag) => tag[0] === 'E')?.[1]!;
|
||||
window.location.hash = `arbor/topics/${threadId}`;
|
||||
window.location.hash = `arbor/threads/${threadId}`;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import { ndk, setSigner } from '@/ndk';
|
||||
import type { ArxInputChangeEvent } from '@components/General/Input';
|
||||
import { animate } from '@lit-labs/motion';
|
||||
import { randomBytes } from '@noble/ciphers/webcrypto';
|
||||
import { NDKEvent, NDKKind, NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
||||
import * as nip06 from '@nostr/tools/nip06';
|
||||
import * as nip19 from '@nostr/tools/nip19';
|
||||
import * as nip49 from '@nostr/tools/nip49';
|
||||
import * as nostrTools from '@nostr/tools/pure';
|
||||
import { encodeBase64 } from '@std/encoding/base64';
|
||||
|
@ -12,18 +9,23 @@ import { LitElement, css, html } from 'lit';
|
|||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
|
||||
import { ndk, setSigner } from '@/ndk';
|
||||
import '@components/General/Button';
|
||||
import '@components/General/Fieldset';
|
||||
import '@components/General/Input';
|
||||
import '@components/LoadingView';
|
||||
import '@components/ProgressSteps';
|
||||
import '@components/RelayLogs';
|
||||
import '@components/Setup/CCNList';
|
||||
import { NDKEvent, NDKKind, NDKPrivateKeySigner, NDKRelay, NDKRelaySet } from '@nostr-dev-kit/ndk';
|
||||
import { nip19 } from '@nostr/tools';
|
||||
|
||||
@customElement('arx-initial-setup')
|
||||
export class InitialSetup extends LitElement {
|
||||
@state() private currentPage = 1;
|
||||
@state() private isAnimating = false;
|
||||
@state() private seedPhrase = '';
|
||||
@state() private communityName = '';
|
||||
@state() private userName = '';
|
||||
@state() private profileImage = '';
|
||||
@state() private lightningAddress = '';
|
||||
|
@ -32,8 +34,10 @@ export class InitialSetup extends LitElement {
|
|||
pid: null,
|
||||
logs: [],
|
||||
};
|
||||
@state() private selectedCCN: string | undefined;
|
||||
@state() private ccnList: { name: string; pubkey: string }[] = [];
|
||||
|
||||
private readonly pageLabels = ['Welcome', 'Seed Phrase', 'Relay Setup', 'Profile', 'Complete'];
|
||||
private readonly pageLabels = ['Welcome', 'Relay Setup', 'Seed Phrase', 'Profile', 'Complete'];
|
||||
|
||||
get encryptionPassphrase() {
|
||||
let encryptionPassphrase = localStorage.getItem('encryption_key');
|
||||
|
@ -212,10 +216,30 @@ export class InitialSetup extends LitElement {
|
|||
}, 300);
|
||||
}
|
||||
|
||||
private nextStep() {
|
||||
if (this.currentPage === 1) return this.handleNavigation(2);
|
||||
if (this.currentPage === 2) {
|
||||
if (this.selectedCCN) return this.handleNavigation(4);
|
||||
return this.handleNavigation(3);
|
||||
}
|
||||
if (this.currentPage === 3) return this.handleNavigation(4);
|
||||
if (this.currentPage === 4) return this.goToFinalStep();
|
||||
}
|
||||
|
||||
private previousStep() {
|
||||
if (this.currentPage === 2) return this.handleNavigation(1);
|
||||
if (this.currentPage === 3) return this.handleNavigation(2);
|
||||
if (this.currentPage === 4) return this.handleNavigation(3);
|
||||
}
|
||||
|
||||
private onSeedPhraseInput(event: ArxInputChangeEvent) {
|
||||
this.seedPhrase = event.detail.value;
|
||||
}
|
||||
|
||||
private onCommunityNameInput(event: ArxInputChangeEvent) {
|
||||
this.communityName = event.detail.value;
|
||||
}
|
||||
|
||||
private generateSeedPhrase() {
|
||||
this.seedPhrase = nip06.generateSeedWords();
|
||||
}
|
||||
|
@ -227,7 +251,12 @@ export class InitialSetup extends LitElement {
|
|||
return true;
|
||||
}
|
||||
|
||||
private renderPageOne() {
|
||||
private isValidCommunityName() {
|
||||
const trimmedName = this.communityName.trim();
|
||||
return trimmedName.length > 0;
|
||||
}
|
||||
|
||||
private renderWelcomePage() {
|
||||
return html`
|
||||
<main class="welcome-container" ${animate()}>
|
||||
<arx-progress-steps
|
||||
|
@ -253,35 +282,139 @@ export class InitialSetup extends LitElement {
|
|||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<arx-button
|
||||
label="Share Feedback"
|
||||
@click=${() => window.open('https://arx-ccn.com/eve-feedback')}
|
||||
>
|
||||
<iconify-icon slot="prefix" icon="mdi:feedback"></iconify-icon>
|
||||
</arx-button>
|
||||
<arx-button
|
||||
variant="secondary"
|
||||
label="Report a Bug"
|
||||
@click=${() => window.open('https://arx-ccn.com/report-eve-bug')}
|
||||
>
|
||||
<iconify-icon slot="prefix" icon="mdi:bug"></iconify-icon>
|
||||
</arx-button>
|
||||
</section>
|
||||
|
||||
<div class="navigation">
|
||||
<span></span>
|
||||
<arx-button
|
||||
variant="primary"
|
||||
label="Next"
|
||||
@click=${() => this.handleNavigation(2)}
|
||||
@click=${() => this.nextStep()}
|
||||
></arx-button>
|
||||
</div>
|
||||
</main>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderPageTwo() {
|
||||
private renderRelaySetupPage() {
|
||||
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>
|
||||
During this alpha phase, manual relay configuration is required.
|
||||
This process will be automated in future releases.
|
||||
</p>
|
||||
<p>Please press the button below to start the relay.</p>
|
||||
<arx-button
|
||||
variant="primary"
|
||||
label=${this.relayStatus.running ? 'Relay Running' : 'Start Relay'}
|
||||
?disabled=${this.relayStatus.running}
|
||||
@click=${() => this.startRelay()}
|
||||
>
|
||||
${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>
|
||||
<arx-relay-logs .logs=${this.relayStatus.logs}></arx-relay-logs>
|
||||
<arx-setup-ccn-list @ccn-selected=${this.onCCNSelected} .ccns=${this.ccnList}></arx-setup-ccn-list>`,
|
||||
)}
|
||||
<p>
|
||||
Having trouble? Our team is here to help if you encounter any
|
||||
issues.
|
||||
</p>
|
||||
<p>Click Continue once the relay is running.</p>
|
||||
</section>
|
||||
|
||||
<div class="navigation">
|
||||
<arx-button
|
||||
@click=${() => this.previousStep()}
|
||||
variant="secondary"
|
||||
label="Back"
|
||||
>
|
||||
</arx-button>
|
||||
<arx-button
|
||||
@click=${() => this.nextStep()}
|
||||
variant="primary"
|
||||
?disabled=${!this.relayStatus.running}
|
||||
label=${this.selectedCCN ? 'Continue' : 'Create CCN'}
|
||||
>
|
||||
</arx-button>
|
||||
</div>
|
||||
</main>
|
||||
`;
|
||||
}
|
||||
|
||||
private onCCNSelected(e: CustomEvent<{ ccn: string }>) {
|
||||
this.selectedCCN = e.detail.ccn;
|
||||
}
|
||||
|
||||
private async startRelay() {
|
||||
await window.relay.start(this.encryptionPassphrase);
|
||||
await this.updateRelayStatus();
|
||||
await new Promise((resolve) => {
|
||||
const ws = new WebSocket('ws://localhost:6942');
|
||||
ws.onopen = () => {
|
||||
ws.send(JSON.stringify(['CCN', 'LIST']));
|
||||
};
|
||||
ws.onmessage = ({ data }) => {
|
||||
const responseData = JSON.parse(data);
|
||||
if (responseData[0] !== 'OK' || responseData[1] !== 'CCN LIST' || responseData[2] !== true) return;
|
||||
this.ccnList = JSON.parse(responseData[3]);
|
||||
resolve(true);
|
||||
ws.close();
|
||||
};
|
||||
ws.onerror = () => {
|
||||
resolve(false);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private async updateRelayStatus() {
|
||||
this.relayStatus = await window.relay.getStatus();
|
||||
if (this.relayStatus.running) setTimeout(() => this.updateRelayStatus(), 2000);
|
||||
}
|
||||
|
||||
private async createCCN() {
|
||||
await new Promise((resolve) => {
|
||||
const ws = new WebSocket('ws://localhost:6942');
|
||||
ws.onopen = () => {
|
||||
ws.send(
|
||||
JSON.stringify([
|
||||
'CCN',
|
||||
'CREATE',
|
||||
{
|
||||
name: this.communityName,
|
||||
seed: this.seedPhrase,
|
||||
},
|
||||
]),
|
||||
);
|
||||
};
|
||||
ws.onmessage = ({ data }) => {
|
||||
const responseData = JSON.parse(data);
|
||||
if (responseData[0] !== 'OK' || responseData[1] !== 'CCN CREATED' || responseData[2] !== true) return;
|
||||
resolve(true);
|
||||
ws.close();
|
||||
this.selectedCCN = JSON.parse(responseData[3]).pubkey;
|
||||
};
|
||||
ws.onerror = () => {
|
||||
resolve(false);
|
||||
};
|
||||
});
|
||||
this.handleNavigation(4);
|
||||
}
|
||||
|
||||
private renderSeedPhrasePage() {
|
||||
return html`
|
||||
<main class="welcome-container" ${animate()}>
|
||||
<arx-progress-steps
|
||||
|
@ -334,89 +467,34 @@ export class InitialSetup extends LitElement {
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<div class="navigation">
|
||||
<arx-button
|
||||
@click=${() => this.handleNavigation(1)}
|
||||
label="Back"
|
||||
variant="secondary"
|
||||
>
|
||||
</arx-button>
|
||||
<arx-button
|
||||
@click=${() => this.handleNavigation(3)}
|
||||
?disabled=${!this.isValidSeedPhrase()}
|
||||
label="Continue"
|
||||
variant="primary"
|
||||
>
|
||||
</arx-button>
|
||||
</div>
|
||||
</main>
|
||||
`;
|
||||
}
|
||||
|
||||
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>
|
||||
<h3>Community Name</h3>
|
||||
|
||||
<p>
|
||||
During this alpha phase, manual relay configuration is required.
|
||||
This process will be automated in future releases.
|
||||
Enter a name for your community. This will be used to identify your
|
||||
community in Eve
|
||||
</p>
|
||||
<p>Please press the button below to start the relay.</p>
|
||||
<arx-button
|
||||
variant="primary"
|
||||
label=${this.relayStatus.running ? 'Relay Running' : 'Start Relay'}
|
||||
?disabled=${this.relayStatus.running}
|
||||
@click=${() => this.startRelay()}
|
||||
>
|
||||
${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>
|
||||
<arx-relay-logs .logs=${this.relayStatus.logs}></arx-relay-logs>`,
|
||||
)}
|
||||
<p>
|
||||
Having trouble? Our team is here to help if you encounter any
|
||||
issues.
|
||||
</p>
|
||||
<p>Click Continue once the relay is running.</p>
|
||||
|
||||
<arx-input
|
||||
type="text"
|
||||
placeholder="Enter Community Name..."
|
||||
.value=${this.communityName}
|
||||
@change=${this.onCommunityNameInput}
|
||||
></arx-input>
|
||||
</section>
|
||||
|
||||
<div class="navigation">
|
||||
<arx-button
|
||||
@click=${() => this.handleNavigation(2)}
|
||||
variant="secondary"
|
||||
@click=${() => this.previousStep()}
|
||||
label="Back"
|
||||
variant="secondary"
|
||||
>
|
||||
</arx-button>
|
||||
<arx-button
|
||||
@click=${() => this.handleNavigation(4)}
|
||||
variant="primary"
|
||||
?disabled=${!this.relayStatus.running}
|
||||
@click=${() => this.createCCN()}
|
||||
?disabled=${!this.isValidSeedPhrase() || !this.isValidCommunityName()}
|
||||
label="Continue"
|
||||
variant="primary"
|
||||
>
|
||||
</arx-button>
|
||||
</div>
|
||||
|
@ -432,7 +510,7 @@ export class InitialSetup extends LitElement {
|
|||
this.profileImage = e.detail.value;
|
||||
}
|
||||
|
||||
private renderPageFour() {
|
||||
private renderProfileSetupPage() {
|
||||
return html`
|
||||
<main class="welcome-container" ${animate()}>
|
||||
<arx-progress-steps
|
||||
|
@ -473,13 +551,13 @@ export class InitialSetup extends LitElement {
|
|||
</section>
|
||||
<div class="navigation">
|
||||
<arx-button
|
||||
@click=${() => this.handleNavigation(3)}
|
||||
@click=${() => this.previousStep()}
|
||||
variant="secondary"
|
||||
label="Back"
|
||||
>
|
||||
</arx-button>
|
||||
<arx-button
|
||||
@click=${() => this.goToFinalStep()}
|
||||
@click=${() => this.nextStep()}
|
||||
variant="primary"
|
||||
label="Next"
|
||||
>
|
||||
|
@ -490,17 +568,34 @@ export class InitialSetup extends LitElement {
|
|||
}
|
||||
|
||||
private async goToFinalStep() {
|
||||
await new Promise((resolve) => {
|
||||
const ws = new WebSocket('ws://localhost:6942');
|
||||
ws.onopen = () => {
|
||||
ws.send(
|
||||
JSON.stringify([
|
||||
'CCN',
|
||||
'ACTIVATE',
|
||||
{
|
||||
pubkey: this.selectedCCN,
|
||||
},
|
||||
]),
|
||||
);
|
||||
};
|
||||
ws.onmessage = ({ data }) => {
|
||||
const responseData = JSON.parse(data);
|
||||
if (responseData[0] !== 'OK' || responseData[1] !== 'CCN ACTIVATED' || responseData[2] !== true) return;
|
||||
resolve(true);
|
||||
};
|
||||
ws.onerror = () => {
|
||||
resolve(false);
|
||||
};
|
||||
});
|
||||
const randomPrivateKey = nostrTools.generateSecretKey();
|
||||
const encryptedNsec = nip49.encrypt(randomPrivateKey, this.encryptionPassphrase);
|
||||
const npub = nip19.npubEncode(nostrTools.getPublicKey(randomPrivateKey));
|
||||
|
||||
this.lightningAddress = `${npub}@npub.cash`;
|
||||
|
||||
localStorage.setItem('ncryptsec', encryptedNsec);
|
||||
|
||||
setSigner(new NDKPrivateKeySigner(randomPrivateKey));
|
||||
await ndk.connect(5000);
|
||||
|
||||
await ndk.connect(10000);
|
||||
const event = new NDKEvent(ndk);
|
||||
event.kind = NDKKind.Metadata;
|
||||
event.content = JSON.stringify({
|
||||
|
@ -509,12 +604,13 @@ export class InitialSetup extends LitElement {
|
|||
lud16: this.lightningAddress,
|
||||
});
|
||||
await event.sign();
|
||||
await event.publish();
|
||||
|
||||
const relaySet = new NDKRelaySet(new Set([new NDKRelay('ws://localhost:6942', undefined, ndk)]), ndk);
|
||||
await event.publish(relaySet, 10000);
|
||||
localStorage.setItem('ncryptsec', encryptedNsec);
|
||||
this.handleNavigation(5);
|
||||
}
|
||||
|
||||
private renderPageFive() {
|
||||
private renderFinalPage() {
|
||||
return html`
|
||||
<main class="welcome-container" ${animate()}>
|
||||
<arx-progress-steps
|
||||
|
@ -539,7 +635,7 @@ export class InitialSetup extends LitElement {
|
|||
|
||||
<div class="navigation">
|
||||
<arx-button
|
||||
@click=${() => this.handleNavigation(4)}
|
||||
@click=${() => this.previousStep()}
|
||||
variant="secondary"
|
||||
label="Back"
|
||||
>
|
||||
|
@ -571,15 +667,15 @@ export class InitialSetup extends LitElement {
|
|||
override render() {
|
||||
switch (this.currentPage) {
|
||||
case 1:
|
||||
return this.renderPageOne();
|
||||
return this.renderWelcomePage();
|
||||
case 2:
|
||||
return this.renderPageTwo();
|
||||
return this.renderRelaySetupPage();
|
||||
case 3:
|
||||
return this.renderPageThree();
|
||||
return this.renderSeedPhrasePage();
|
||||
case 4:
|
||||
return this.renderPageFour();
|
||||
return this.renderProfileSetupPage();
|
||||
case 5:
|
||||
return this.renderPageFive();
|
||||
return this.renderFinalPage();
|
||||
default:
|
||||
return html`<div class="welcome-container">
|
||||
<arx-loading-view></arx-loading-view>
|
||||
|
|
56
src/components/Setup/CCNList.ts
Normal file
56
src/components/Setup/CCNList.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import '@components/General/Button';
|
||||
import '@components/General/Select';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement('arx-setup-ccn-list')
|
||||
export class CCNList extends LitElement {
|
||||
@property({ type: Array }) ccns: { name: string; pubkey: string }[] = [];
|
||||
|
||||
static override styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
|
||||
@state() private selectedCCN: string | undefined;
|
||||
|
||||
private _valueMapper = (ccn: { name: string; pubkey: string }) => ccn.pubkey;
|
||||
private _textMapper = (ccn: { name: string; pubkey: string }) => ccn.name;
|
||||
|
||||
private _handleCCNSelected(pubkey: string | undefined) {
|
||||
this.selectedCCN = pubkey;
|
||||
this.dispatchEvent(new CustomEvent('ccn-selected', { detail: { ccn: this.selectedCCN } }));
|
||||
}
|
||||
|
||||
override render() {
|
||||
if (this.ccns.length === 0)
|
||||
return html`
|
||||
<p>No CCNs found in the relay. You will be asked to setup a CCN in the next step.</p>
|
||||
`;
|
||||
|
||||
if (this.ccns.length === 1)
|
||||
return html`
|
||||
<div>
|
||||
<h2>CCN Found</h2>
|
||||
<p>We found one CCN in your relay, which likely means you've used Eve before or there was an update introducing new setup steps. You can use this CCN to proceed with the setup, or create a new one.</p>
|
||||
<p>CCN Name: ${this.ccns[0].name}</p>
|
||||
<arx-button variant=${this.selectedCCN === this.ccns[0].pubkey ? 'accent' : 'secondary'} @click="${() => this._handleCCNSelected(this.ccns[0].pubkey)}" label="Use This CCN"></arx-button>
|
||||
<arx-button variant=${this.selectedCCN === undefined ? 'accent' : 'secondary'} @click="${() => this._handleCCNSelected(undefined)}" label="Create New CCN"></arx-button>
|
||||
</div>
|
||||
`;
|
||||
return html`
|
||||
<div>
|
||||
<h2>CCNs</h2>
|
||||
<p>We found the following CCNs in your relay, which likely means you've used Eve before or there was an update introducing new setup steps. You can quickly choose one of these CCNs to proceed with the setup, or create a new one.</p>
|
||||
<arx-select
|
||||
.options="${this.ccns}"
|
||||
.valueMapper="${this._valueMapper}"
|
||||
.textMapper="${this._textMapper}"
|
||||
@change="${(e: CustomEvent<{ value: string }>) => this._handleCCNSelected(e.detail.value)}"
|
||||
></arx-select>
|
||||
<arx-button variant=${this.selectedCCN === undefined ? 'accent' : 'secondary'} @click="${() => this._handleCCNSelected(undefined)}" label="Create New CCN"></arx-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
|
@ -20,31 +20,31 @@ export default class Sidebar extends LitElement {
|
|||
apps = [
|
||||
{
|
||||
id: 1,
|
||||
href: 'beacon',
|
||||
name: 'Beacon',
|
||||
href: 'calendar',
|
||||
name: 'Calendar',
|
||||
color: '#FF8C00',
|
||||
icon: 'fa-solid:sun',
|
||||
icon: 'arx:calendar',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
href: 'arbor',
|
||||
name: 'Arbor',
|
||||
color: '#FF4040',
|
||||
icon: 'fa-solid:tree',
|
||||
icon: 'arx:arbor',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
href: 'wallet',
|
||||
name: 'Wallet',
|
||||
color: '#1E90FF',
|
||||
icon: 'fa-solid:spa',
|
||||
icon: 'arx:wallet',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
href: 'settings',
|
||||
name: 'Settings',
|
||||
color: '#7B68EE',
|
||||
icon: 'fa-solid:tools',
|
||||
icon: 'arx:settings',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue