📚✨ Enhance project setup & maintenance workflows
- 📝 Add comprehensive README.md, CONTRIBUTING.md, and 🔒 SECURITY.md documentation - 🔧 Integrate code formatting tool and refactor existing codebase to meet style guidelines - ⬆️ Update project dependencies to latest stable versions - 🤖 Implement pre-commit hook for automated code formatting #documentation #tooling #maintenance
This commit is contained in:
parent
25b3972f8b
commit
18e4ad7629
47 changed files with 1027 additions and 568 deletions
|
@ -1,9 +1,9 @@
|
|||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import "@components/AppIcon";
|
||||
import '@components/AppIcon';
|
||||
|
||||
@customElement("arx-app-grid")
|
||||
@customElement('arx-app-grid')
|
||||
export class AppGrid extends LitElement {
|
||||
@property()
|
||||
apps: {
|
||||
|
@ -59,7 +59,7 @@ export class AppGrid extends LitElement {
|
|||
.href=${app.href}
|
||||
.name=${app.name}
|
||||
></arx-app-icon>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import "@components/EveLink";
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement("arx-app-icon")
|
||||
@customElement('arx-app-icon')
|
||||
export class AppIcon extends LitElement {
|
||||
@property()
|
||||
icon: string | undefined;
|
||||
|
||||
@property()
|
||||
color = "#ff9900";
|
||||
color = '#ff9900';
|
||||
|
||||
@property()
|
||||
href = "#";
|
||||
href = '#';
|
||||
|
||||
@property()
|
||||
name = "App";
|
||||
name = 'App';
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
|
@ -83,15 +83,17 @@ export class AppIcon extends LitElement {
|
|||
return html`
|
||||
<arx-eve-link href="${this.href}" class="app-icon">
|
||||
<div class="icon" style="background-color: ${this.color}">
|
||||
${this.icon
|
||||
? html`<iconify-icon
|
||||
${
|
||||
this.icon
|
||||
? html`<iconify-icon
|
||||
icon="${this.icon}"
|
||||
class="app-icon"
|
||||
width="48"
|
||||
height="48"
|
||||
color="white"
|
||||
></iconify-icon>`
|
||||
: ""}
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
<span class="app-name">${this.name}</span>
|
||||
</arx-eve-link>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { html, css, LitElement } from 'lit';
|
||||
import { property, customElement } from 'lit/decorators.js';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import './BreadcrumbsItem';
|
||||
|
||||
@customElement('arx-breadcrumbs')
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import "@components/EveLink";
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement("arx-breadcrumbs-item")
|
||||
@customElement('arx-breadcrumbs-item')
|
||||
export class BreadcrumbsItem extends LitElement {
|
||||
@property() text = "";
|
||||
@property() text = '';
|
||||
@property() href?: string;
|
||||
@property() index = 0;
|
||||
|
||||
|
@ -37,14 +37,14 @@ export class BreadcrumbsItem extends LitElement {
|
|||
override render() {
|
||||
return html`
|
||||
<li>
|
||||
${this.index > 0
|
||||
? html`<span class="separator" aria-hidden="true">/</span>`
|
||||
: ""}
|
||||
${this.href
|
||||
? html`<arx-eve-link class="link" href=${this.href}
|
||||
${this.index > 0 ? html`<span class="separator" aria-hidden="true">/</span>` : ''}
|
||||
${
|
||||
this.href
|
||||
? html`<arx-eve-link class="link" href=${this.href}
|
||||
>${this.text}</arx-eve-link
|
||||
>`
|
||||
: html`<span class="secondary">${this.text}</span>`}
|
||||
: html`<span class="secondary">${this.text}</span>`
|
||||
}
|
||||
</li>
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { html, LitElement, css } from 'lit';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
@customElement('arx-error-view')
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-eve-link")
|
||||
@customElement('arx-eve-link')
|
||||
export class EveLink extends LitElement {
|
||||
@property({ type: String }) href = "#";
|
||||
@property({ type: String }) target = "";
|
||||
@property({ type: String }) rel = "";
|
||||
@property({ type: String }) href = '#';
|
||||
@property({ type: String }) target = '';
|
||||
@property({ type: String }) rel = '';
|
||||
|
||||
get hrefValue() {
|
||||
let href = this.href;
|
||||
if (href.startsWith("javascript:")) return href;
|
||||
if (href.startsWith("eve://")) href = href.replace("eve://", "#");
|
||||
if (href.startsWith("/")) href = href.replace("/", "#");
|
||||
if (!href.startsWith("#")) href = `#${href}`;
|
||||
if (href.startsWith('javascript:')) return href;
|
||||
if (href.startsWith('eve://')) href = href.replace('eve://', '#');
|
||||
if (href.startsWith('/')) href = href.replace('/', '#');
|
||||
if (!href.startsWith('#')) href = `#${href}`;
|
||||
return href;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement } from "lit/decorators.js";
|
||||
import formatDateTime from "@utils/formatDateTime";
|
||||
import formatDateTime from '@utils/formatDateTime';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import "@components/MarkdownContent";
|
||||
import '@components/MarkdownContent';
|
||||
|
||||
@customElement("arx-forum-post")
|
||||
@customElement('arx-forum-post')
|
||||
export class ForumPost extends LitElement {
|
||||
@property({ type: String }) override id = "";
|
||||
@property({ type: String }) topicId = "";
|
||||
@property({ type: String }) npub = "";
|
||||
@property({ type: String }) override id = '';
|
||||
@property({ type: String }) topicId = '';
|
||||
@property({ type: String }) npub = '';
|
||||
@property({ type: Date }) date = new Date();
|
||||
@property({ type: String }) content = "";
|
||||
@property({ type: String }) content = '';
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
|
@ -82,13 +82,13 @@ export class ForumPost extends LitElement {
|
|||
</div>
|
||||
<div>
|
||||
<arx-markdown-content
|
||||
.content=${this.content || "no content"}
|
||||
.content=${this.content || 'no content'}
|
||||
></arx-markdown-content>
|
||||
</div>
|
||||
<div>
|
||||
<arx-phora-button
|
||||
href="#"
|
||||
@click=${() => alert("TODO")}
|
||||
@click=${() => alert('TODO')}
|
||||
class="disabled"
|
||||
>
|
||||
<iconify-icon size="32" icon="mdi:reply"></iconify-icon>
|
||||
|
@ -100,7 +100,7 @@ export class ForumPost extends LitElement {
|
|||
</arx-phora-button>
|
||||
<arx-phora-button
|
||||
href="#"
|
||||
@click=${() => alert("TODO")}
|
||||
@click=${() => alert('TODO')}
|
||||
class="disabled"
|
||||
>
|
||||
<iconify-icon size="32" icon="bxs:zap"></iconify-icon>
|
||||
|
@ -108,7 +108,7 @@ export class ForumPost extends LitElement {
|
|||
</arx-phora-button>
|
||||
<arx-phora-button
|
||||
href="#"
|
||||
@click=${() => alert("TODO")}
|
||||
@click=${() => alert('TODO')}
|
||||
class="disabled"
|
||||
>
|
||||
<iconify-icon
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-header")
|
||||
@customElement('arx-header')
|
||||
export class Header extends LitElement {
|
||||
@property({ type: String }) override title = "Eve";
|
||||
@property({ type: String }) url = "eve://home";
|
||||
@property({ type: String }) override title = 'Eve';
|
||||
@property({ type: String }) url = 'eve://home';
|
||||
|
||||
@property({ type: Boolean }) canGoBack = false;
|
||||
@property({ type: Boolean }) canGoForward = false;
|
||||
|
||||
private searchQuery = "";
|
||||
private searchQuery = '';
|
||||
private searchInput: HTMLInputElement | null = null;
|
||||
|
||||
static override styles = [
|
||||
|
@ -95,15 +95,15 @@ export class Header extends LitElement {
|
|||
<header>
|
||||
<div class="nav-buttons">
|
||||
<button
|
||||
class=${this.canGoBack ? "" : "disabled"}
|
||||
@click=${() => this.dispatchEvent(new CustomEvent("go-back"))}
|
||||
class=${this.canGoBack ? '' : 'disabled'}
|
||||
@click=${() => this.dispatchEvent(new CustomEvent('go-back'))}
|
||||
aria-label="Go back"
|
||||
>
|
||||
<iconify-icon icon="material-symbols:arrow-back"></iconify-icon>
|
||||
</button>
|
||||
<button
|
||||
class=${this.canGoForward ? "" : "disabled"}
|
||||
@click=${() => this.dispatchEvent(new CustomEvent("go-forward"))}
|
||||
class=${this.canGoForward ? '' : 'disabled'}
|
||||
@click=${() => this.dispatchEvent(new CustomEvent('go-forward'))}
|
||||
aria-label="Go forward"
|
||||
>
|
||||
<iconify-icon icon="material-symbols:arrow-forward"></iconify-icon>
|
||||
|
@ -126,8 +126,8 @@ export class Header extends LitElement {
|
|||
}
|
||||
|
||||
private handleSearch(e: KeyboardEvent) {
|
||||
if (e.key !== "Enter") return;
|
||||
const hash = (e.target as HTMLInputElement).value.replace("eve://", "#");
|
||||
if (e.key !== 'Enter') return;
|
||||
const hash = (e.target as HTMLInputElement).value.replace('eve://', '#');
|
||||
window.location.hash = hash;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { animate } from "@lit-labs/motion";
|
||||
import * as nostrTools from "@nostr/tools/pure";
|
||||
import * as nip06 from "@nostr/tools/nip06";
|
||||
import * as nip19 from "@nostr/tools/nip19";
|
||||
import * as nip49 from "@nostr/tools/nip49";
|
||||
import { ndk, setSigner } from "@/ndk";
|
||||
import { NDKEvent, NDKKind, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
||||
import { encodeBase64 } from "@std/encoding/base64";
|
||||
import { randomBytes } from "@noble/ciphers/webcrypto";
|
||||
import { ndk, setSigner } from '@/ndk';
|
||||
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';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-initial-setup")
|
||||
@customElement('arx-initial-setup')
|
||||
export class InitialSetup extends LitElement {
|
||||
@state() private currentPage = 1;
|
||||
@state() private isAnimating = false;
|
||||
@state() private seedPhrase = "";
|
||||
@state() private userName = "";
|
||||
@state() private profileImage = "";
|
||||
@state() private lightningAddress = "";
|
||||
@state() private seedPhrase = '';
|
||||
@state() private userName = '';
|
||||
@state() private profileImage = '';
|
||||
@state() private lightningAddress = '';
|
||||
|
||||
get encryptionPassphrase() {
|
||||
let encryptionPassphrase = localStorage.getItem("encryption_key");
|
||||
let encryptionPassphrase = localStorage.getItem('encryption_key');
|
||||
if (!encryptionPassphrase) {
|
||||
encryptionPassphrase = encodeBase64(randomBytes(32));
|
||||
localStorage.setItem("encryption_key", encryptionPassphrase);
|
||||
localStorage.setItem('encryption_key', encryptionPassphrase);
|
||||
}
|
||||
return encryptionPassphrase;
|
||||
}
|
||||
|
@ -285,7 +285,9 @@ export class InitialSetup extends LitElement {
|
|||
if (this.isAnimating) return;
|
||||
this.isAnimating = true;
|
||||
this.currentPage = page;
|
||||
setTimeout(() => (this.isAnimating = false), 300);
|
||||
setTimeout(() => {
|
||||
this.isAnimating = false;
|
||||
}, 300);
|
||||
}
|
||||
|
||||
private onSeedPhraseInput(event: Event) {
|
||||
|
@ -297,9 +299,9 @@ export class InitialSetup extends LitElement {
|
|||
}
|
||||
|
||||
private isValidSeedPhrase() {
|
||||
const words = this.seedPhrase.split(" ");
|
||||
const words = this.seedPhrase.split(' ');
|
||||
if (words.length !== 12) return false;
|
||||
if (!nip06.validateWords(words.join(" "))) return false;
|
||||
if (!nip06.validateWords(words.join(' '))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -574,15 +576,12 @@ export class InitialSetup extends LitElement {
|
|||
|
||||
private async goToFinalStep() {
|
||||
const randomPrivateKey = nostrTools.generateSecretKey();
|
||||
const encryptedNsec = nip49.encrypt(
|
||||
randomPrivateKey,
|
||||
this.encryptionPassphrase
|
||||
);
|
||||
const encryptedNsec = nip49.encrypt(randomPrivateKey, this.encryptionPassphrase);
|
||||
const npub = nip19.npubEncode(nostrTools.getPublicKey(randomPrivateKey));
|
||||
|
||||
if (!this.lightningAddress) this.lightningAddress = `${npub}@npub.cash`;
|
||||
|
||||
localStorage.setItem("ncryptsec", encryptedNsec);
|
||||
localStorage.setItem('ncryptsec', encryptedNsec);
|
||||
|
||||
setSigner(new NDKPrivateKeySigner(randomPrivateKey));
|
||||
await ndk.connect(5000);
|
||||
|
@ -615,11 +614,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>
|
||||
${
|
||||
this.profileImage
|
||||
? html` <p>
|
||||
Your profile image is: <img .src=${this.profileImage} />
|
||||
</p>`
|
||||
: ""}
|
||||
: ''
|
||||
}
|
||||
<p>Your lightning address is: <b>${this.lightningAddress}</b></p>
|
||||
</section>
|
||||
|
||||
|
@ -638,7 +639,7 @@ export class InitialSetup extends LitElement {
|
|||
|
||||
finish() {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("finish", {
|
||||
new CustomEvent('finish', {
|
||||
detail: {
|
||||
userName: this.userName,
|
||||
profileImage: this.profileImage,
|
||||
|
@ -646,7 +647,7 @@ export class InitialSetup extends LitElement {
|
|||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { html, LitElement } from 'lit';
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
|
||||
@customElement('arx-loading-view')
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { css, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
||||
import MarkdownIt, { type StateCore, type Token } from "markdown-it";
|
||||
import { LitElement, css } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
||||
import MarkdownIt, { type StateCore, type Token } from 'markdown-it';
|
||||
|
||||
function nostrPlugin(md: MarkdownIt): void {
|
||||
const npubRegex = /(npub[0-9a-zA-Z]{59})/g;
|
||||
|
||||
md.core.ruler.after("inline", "nostr_npub", (state: StateCore): boolean => {
|
||||
md.core.ruler.after('inline', 'nostr_npub', (state: StateCore): boolean => {
|
||||
for (const token of state.tokens) {
|
||||
if (token.type === "inline" && token.children) {
|
||||
if (token.type === 'inline' && token.children) {
|
||||
for (let i = 0; i < token.children.length; i++) {
|
||||
const child = token.children[i];
|
||||
|
||||
if (child.type === "text") {
|
||||
if (child.type === 'text') {
|
||||
const matches = child.content.match(npubRegex);
|
||||
if (!matches) continue;
|
||||
|
||||
|
@ -24,26 +24,26 @@ function nostrPlugin(md: MarkdownIt): void {
|
|||
// @ts-ignore this is an issue with the types
|
||||
(match: string, npub: string, offset: number) => {
|
||||
if (offset > lastIndex) {
|
||||
const textToken = new state.Token("text", "", 0);
|
||||
const textToken = new state.Token('text', '', 0);
|
||||
textToken.content = child.content.slice(lastIndex, offset);
|
||||
newTokens.push(textToken);
|
||||
}
|
||||
|
||||
const linkOpen = new state.Token("link_open", "a", 1);
|
||||
linkOpen.attrs = [["href", `nostr:${npub}`]];
|
||||
const linkOpen = new state.Token('link_open', 'a', 1);
|
||||
linkOpen.attrs = [['href', `nostr:${npub}`]];
|
||||
|
||||
const text = new state.Token("text", "", 0);
|
||||
const text = new state.Token('text', '', 0);
|
||||
text.content = npub;
|
||||
|
||||
const linkClose = new state.Token("link_close", "a", -1);
|
||||
const linkClose = new state.Token('link_close', 'a', -1);
|
||||
|
||||
newTokens.push(linkOpen, text, linkClose);
|
||||
lastIndex = offset + match.length;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (lastIndex < child.content.length) {
|
||||
const textToken = new state.Token("text", "", 0);
|
||||
const textToken = new state.Token('text', '', 0);
|
||||
textToken.content = child.content.slice(lastIndex);
|
||||
newTokens.push(textToken);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ function nostrPlugin(md: MarkdownIt): void {
|
|||
});
|
||||
}
|
||||
|
||||
@customElement("arx-markdown-content")
|
||||
@customElement('arx-markdown-content')
|
||||
export class MarkdownContent extends LitElement {
|
||||
private md = new MarkdownIt({
|
||||
html: false,
|
||||
|
@ -69,7 +69,7 @@ export class MarkdownContent extends LitElement {
|
|||
});
|
||||
|
||||
@property({ type: String })
|
||||
content = "";
|
||||
content = '';
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { css, html, LitElement } from 'lit-element';
|
||||
import { LitElement, css, html } from 'lit-element';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
type AvatarSize = 'short' | 'medium' | 'large' | 'huge';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { html, css, LitElement } from 'lit';
|
||||
import { property, customElement, state } from 'lit/decorators.js';
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { getUserProfile } from '../ndk';
|
||||
import '@components/profiles/ShortProfile';
|
||||
import '@components/profiles/MediumProfile';
|
||||
|
@ -11,11 +11,7 @@ import '@components/profiles/CardProfile';
|
|||
export class NostrProfile extends LitElement {
|
||||
@property() npub = '';
|
||||
|
||||
@property({ reflect: true }) renderType:
|
||||
| 'short'
|
||||
| 'medium'
|
||||
| 'large'
|
||||
| 'card' = 'short';
|
||||
@property({ reflect: true }) renderType: 'short' | 'medium' | 'large' | 'card' = 'short';
|
||||
|
||||
@state()
|
||||
private profile: NDKUserProfile | undefined = undefined;
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import "@components/EveLink";
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement("arx-phora-button")
|
||||
@customElement('arx-phora-button')
|
||||
export class PhoraButton extends LitElement {
|
||||
@property({ type: String }) href = "";
|
||||
@property({ type: String }) target = "";
|
||||
@property({ type: String }) rel = "";
|
||||
@property({ type: String }) href = '';
|
||||
@property({ type: String }) target = '';
|
||||
@property({ type: String }) rel = '';
|
||||
@property({ type: Boolean }) disabled = false;
|
||||
|
||||
get hrefValue() {
|
||||
if (!this.href || this.disabled) return "javascript:void(0)";
|
||||
if (!this.href || this.disabled) return 'javascript:void(0)';
|
||||
return this.href;
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,7 @@ export class PhoraButton extends LitElement {
|
|||
.href=${this.hrefValue}
|
||||
.target=${this.target}
|
||||
.rel=${this.rel}
|
||||
class="${this.disabled ? "disabled" : ""}"
|
||||
class="${this.disabled ? 'disabled' : ''}"
|
||||
>
|
||||
<slot></slot>
|
||||
</arx-eve-link>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-phora-forum-category")
|
||||
@customElement('arx-phora-forum-category')
|
||||
export class PhoraForumCategory extends LitElement {
|
||||
@property({ type: String }) override title = "";
|
||||
@property({ type: String }) override id = "";
|
||||
@property({ type: String }) override title = '';
|
||||
@property({ type: String }) override id = '';
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement } from "lit/decorators.js";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import "@components/EveLink";
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement("arx-phora-forum-topic")
|
||||
@customElement('arx-phora-forum-topic')
|
||||
export class PhoraForumTopic extends LitElement {
|
||||
static override styles = [
|
||||
css`
|
||||
|
@ -165,19 +165,19 @@ export class PhoraForumTopic extends LitElement {
|
|||
`,
|
||||
];
|
||||
|
||||
@property({ type: String }) override id = "";
|
||||
@property({ type: String }) override title = "";
|
||||
@property({ type: String }) description = "";
|
||||
@property({ type: String }) override id = '';
|
||||
@property({ type: String }) override title = '';
|
||||
@property({ type: String }) description = '';
|
||||
@property({ type: Number }) posts = 0;
|
||||
@property({ type: String }) lastPostBy = "";
|
||||
@property({ type: String }) lastPostTime = "";
|
||||
@property({ type: String }) lastPostBy = '';
|
||||
@property({ type: String }) lastPostTime = '';
|
||||
@property({ type: Boolean }) isNew = false;
|
||||
@property({ type: Boolean }) isHot = false;
|
||||
|
||||
get status() {
|
||||
if (this.isNew) return "new-status";
|
||||
if (this.isHot) return "hot-status";
|
||||
return "";
|
||||
if (this.isNew) return 'new-status';
|
||||
if (this.isHot) return 'hot-status';
|
||||
return '';
|
||||
}
|
||||
|
||||
override render() {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { getLastBlockHeight } from "@utils/lastBlockHeight";
|
||||
import { getLastBlockHeight } from '@utils/lastBlockHeight';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-bitcoin-block-widget")
|
||||
@customElement('arx-bitcoin-block-widget')
|
||||
export class BitcoinBlockWidget extends LitElement {
|
||||
@state()
|
||||
private lastBlock: number | null = null;
|
||||
|
@ -21,10 +21,7 @@ export class BitcoinBlockWidget extends LitElement {
|
|||
constructor() {
|
||||
super();
|
||||
this.loadBlockHeight();
|
||||
this.timer = window.setInterval(
|
||||
this.loadBlockHeight,
|
||||
this.REFRESH_INTERVAL
|
||||
);
|
||||
this.timer = window.setInterval(this.loadBlockHeight, this.REFRESH_INTERVAL);
|
||||
}
|
||||
|
||||
override disconnectedCallback() {
|
||||
|
@ -38,7 +35,7 @@ export class BitcoinBlockWidget extends LitElement {
|
|||
this.lastBlock = response.height;
|
||||
this.error = null;
|
||||
} catch (error) {
|
||||
this.error = "Failed to load block height";
|
||||
this.error = 'Failed to load block height';
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { html, css, LitElement } from 'lit';
|
||||
import { property, customElement, state } from 'lit/decorators.js';
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { getProfile } from '@utils/profileUtils';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement('arx-nostr-card-profile')
|
||||
export class CardProfile extends LitElement {
|
||||
|
@ -86,7 +86,7 @@ export class CardProfile extends LitElement {
|
|||
.join('\n')
|
||||
.trim()
|
||||
.split(/-+\n/, 2)
|
||||
.filter(section => section.trim() !== '')
|
||||
.filter((section) => section.trim() !== '')
|
||||
.join('\n')
|
||||
.trim();
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { html, css, LitElement } from 'lit';
|
||||
import { property, customElement, state } from 'lit/decorators.js';
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { getProfile } from '@utils/profileUtils';
|
||||
import firstLine from '@utils/firstLine';
|
||||
import { getProfile } from '@utils/profileUtils';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement('arx-nostr-large-profile')
|
||||
export class LargeProfile extends LitElement {
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement, state } from "lit/decorators.js";
|
||||
import type { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||
import { getProfile } from "@utils/profileUtils";
|
||||
import firstLine from "@utils/firstLine";
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import firstLine from '@utils/firstLine';
|
||||
import { getProfile } from '@utils/profileUtils';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
import "@components/EveLink";
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement("arx-nostr-medium-profile")
|
||||
@customElement('arx-nostr-medium-profile')
|
||||
export class MediumProfile extends LitElement {
|
||||
@property() profile!: NDKUserProfile;
|
||||
@property() npub = "";
|
||||
@property() npub = '';
|
||||
|
||||
@state()
|
||||
private displayName = "";
|
||||
private displayName = '';
|
||||
|
||||
@state()
|
||||
private profileUrl = "";
|
||||
private profileUrl = '';
|
||||
|
||||
@state()
|
||||
private truncatedAbout = "";
|
||||
private truncatedAbout = '';
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { property, customElement, state } from "lit/decorators.js";
|
||||
import type { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||
import { getProfile } from "@utils/profileUtils";
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { getProfile } from '@utils/profileUtils';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
import "@components/EveLink";
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement("arx-nostr-short-profile")
|
||||
@customElement('arx-nostr-short-profile')
|
||||
export class ShortProfile extends LitElement {
|
||||
@property() profile!: NDKUserProfile;
|
||||
@property() npub = "";
|
||||
@property() npub = '';
|
||||
|
||||
@state()
|
||||
private displayName = "";
|
||||
private displayName = '';
|
||||
|
||||
@state()
|
||||
private profileUrl = "";
|
||||
private profileUrl = '';
|
||||
|
||||
static override styles = [
|
||||
css`
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
import { app, shell, BrowserWindow, ipcMain } from "electron";
|
||||
import { optimizer, is } from "@electron-toolkit/utils";
|
||||
import { RelayManager } from "./relayManager";
|
||||
import path from "node:path";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { is, optimizer } from '@electron-toolkit/utils';
|
||||
import { BrowserWindow, app, ipcMain, shell } from 'electron';
|
||||
import { RelayManager } from './relayManager';
|
||||
|
||||
const relay = new RelayManager();
|
||||
|
||||
ipcMain.handle("relay:writeSeed", async (_, ...args: any) => {
|
||||
if (!args[0]) throw new Error("No seed provided");
|
||||
ipcMain.handle('relay:writeSeed', async (_, ...args: string[]) => {
|
||||
if (!args[0]) throw new Error('No seed provided');
|
||||
const seed = args[0] as string;
|
||||
let configPath: string;
|
||||
if (process.platform === "darwin") {
|
||||
configPath = path.join(app.getPath("userData"), "arx", "Eve");
|
||||
if (process.platform === 'darwin') {
|
||||
configPath = path.join(app.getPath('userData'), 'arx', 'Eve');
|
||||
} else {
|
||||
configPath = path.join(os.homedir(), ".config", "arx", "Eve");
|
||||
configPath = path.join(os.homedir(), '.config', 'arx', 'Eve');
|
||||
}
|
||||
|
||||
const seedPath = path.join(configPath, "ccn.seed");
|
||||
const seedPath = path.join(configPath, 'ccn.seed');
|
||||
fs.mkdirSync(configPath, { recursive: true });
|
||||
fs.writeFileSync(seedPath, seed);
|
||||
});
|
||||
|
||||
ipcMain.handle("relay:start", (_, ...args: any) => {
|
||||
if (!args[0]) throw new Error("No encryption key provided");
|
||||
const encryptionKey = args[0] as string;
|
||||
ipcMain.handle('relay:start', (_, ...args: string[]) => {
|
||||
if (!args[0]) throw new Error('No encryption key provided');
|
||||
const encryptionKey = args[0];
|
||||
return relay.start(encryptionKey);
|
||||
});
|
||||
|
||||
ipcMain.handle("relay:stop", () => {
|
||||
ipcMain.handle('relay:stop', () => {
|
||||
return relay.stop();
|
||||
});
|
||||
|
||||
ipcMain.handle("relay:status", () => {
|
||||
ipcMain.handle('relay:status', () => {
|
||||
return {
|
||||
running: relay.isRunning,
|
||||
pid: relay.pid,
|
||||
|
@ -40,7 +40,7 @@ ipcMain.handle("relay:status", () => {
|
|||
};
|
||||
});
|
||||
|
||||
ipcMain.handle("relay:getLogs", () => {
|
||||
ipcMain.handle('relay:getLogs', () => {
|
||||
return relay.getLogs();
|
||||
});
|
||||
|
||||
|
@ -51,33 +51,32 @@ function createWindow(): void {
|
|||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, "../preload/preload.mjs"),
|
||||
preload: path.join(__dirname, '../preload/preload.mjs'),
|
||||
sandbox: false,
|
||||
},
|
||||
});
|
||||
|
||||
mainWindow.on("ready-to-show", () => {
|
||||
mainWindow.on('ready-to-show', () => {
|
||||
mainWindow.show();
|
||||
});
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url);
|
||||
return { action: "deny" };
|
||||
return { action: 'deny' };
|
||||
});
|
||||
|
||||
if (is.dev && process.env["ELECTRON_RENDERER_URL"])
|
||||
mainWindow.loadURL(process.env["ELECTRON_RENDERER_URL"]);
|
||||
else mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"));
|
||||
if (is.dev && process.env['ELECTRON_RENDERER_URL']) mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL']);
|
||||
else mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'));
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
app.on("browser-window-created", (_, window) => {
|
||||
app.on('browser-window-created', (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
|
||||
createWindow();
|
||||
});
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
app.on('window-all-closed', () => {
|
||||
app.quit();
|
||||
});
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import { contextBridge, ipcRenderer } from "electron";
|
||||
import { electronAPI } from "@electron-toolkit/preload";
|
||||
import { electronAPI } from '@electron-toolkit/preload';
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
|
||||
if (process.contextIsolated) {
|
||||
try {
|
||||
contextBridge.exposeInMainWorld("electron", electronAPI);
|
||||
contextBridge.exposeInMainWorld("relay", {
|
||||
writeSeed: (seed: string) => ipcRenderer.invoke("relay:writeSeed", seed),
|
||||
start: (encryptionKey: string) =>
|
||||
ipcRenderer.invoke("relay:start", encryptionKey),
|
||||
stop: () => ipcRenderer.invoke("relay:stop"),
|
||||
getStatus: () => ipcRenderer.invoke("relay:status"),
|
||||
getLogs: () => ipcRenderer.invoke("relay:logs"),
|
||||
contextBridge.exposeInMainWorld('electron', electronAPI);
|
||||
contextBridge.exposeInMainWorld('relay', {
|
||||
writeSeed: (seed: string) => ipcRenderer.invoke('relay:writeSeed', seed),
|
||||
start: (encryptionKey: string) => ipcRenderer.invoke('relay:start', encryptionKey),
|
||||
stop: () => ipcRenderer.invoke('relay:stop'),
|
||||
getStatus: () => ipcRenderer.invoke('relay:status'),
|
||||
getLogs: () => ipcRenderer.invoke('relay:logs'),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { spawn, ChildProcess } from "child_process";
|
||||
import { join } from "path";
|
||||
import { is } from "@electron-toolkit/utils";
|
||||
import { type ChildProcess, spawn } from 'node:child_process';
|
||||
import { join } from 'node:path';
|
||||
import { is } from '@electron-toolkit/utils';
|
||||
|
||||
type PackageEnvironment = "flatpak" | "appimage" | "system" | "mac" | "dev";
|
||||
type PackageEnvironment = 'flatpak' | 'appimage' | 'system' | 'mac' | 'dev';
|
||||
|
||||
export class RelayManager {
|
||||
private process: ChildProcess | null;
|
||||
|
@ -49,27 +49,27 @@ export class RelayManager {
|
|||
}
|
||||
|
||||
private detectEnvironment(): PackageEnvironment {
|
||||
if (is.dev) return "dev";
|
||||
if (process.platform === "darwin") return "mac";
|
||||
if (process.env.FLATPAK_ID) return "flatpak";
|
||||
if (process.env.APPIMAGE) return "appimage";
|
||||
return "system";
|
||||
if (is.dev) return 'dev';
|
||||
if (process.platform === 'darwin') return 'mac';
|
||||
if (process.env.FLATPAK_ID) return 'flatpak';
|
||||
if (process.env.APPIMAGE) return 'appimage';
|
||||
return 'system';
|
||||
}
|
||||
|
||||
private getRelayPath(): string {
|
||||
const environment = this.detectEnvironment();
|
||||
|
||||
switch (environment) {
|
||||
case "dev":
|
||||
return join(__dirname, "../../extras/linux/relay");
|
||||
case "mac":
|
||||
return join(process.resourcesPath, "macos", "eve-relay");
|
||||
case "flatpak":
|
||||
return "/app/lib/com.arx_ccn.eve/usr/bin/eve-relay";
|
||||
case "appimage":
|
||||
return join(process.env.APPDIR || "", "usr/bin/eve-relay");
|
||||
case "system":
|
||||
return "/usr/bin/eve-relay";
|
||||
case 'dev':
|
||||
return join(__dirname, '../../extras/linux/relay');
|
||||
case 'mac':
|
||||
return join(process.resourcesPath, 'macos', 'eve-relay');
|
||||
case 'flatpak':
|
||||
return '/app/lib/com.arx_ccn.eve/usr/bin/eve-relay';
|
||||
case 'appimage':
|
||||
return join(process.env.APPDIR || '', 'usr/bin/eve-relay');
|
||||
case 'system':
|
||||
return '/usr/bin/eve-relay';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,16 +82,12 @@ export class RelayManager {
|
|||
|
||||
private restartProcess(): void {
|
||||
if (this.restartAttempts >= this.maxRestartAttempts) {
|
||||
console.error(
|
||||
`Failed to restart relay after ${this.maxRestartAttempts} attempts`
|
||||
);
|
||||
console.error(`Failed to restart relay after ${this.maxRestartAttempts} attempts`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.restartAttempts++;
|
||||
console.log(
|
||||
`Attempting restart #${this.restartAttempts} in ${this.restartDelay}ms...`
|
||||
);
|
||||
console.log(`Attempting restart #${this.restartAttempts} in ${this.restartDelay}ms...`);
|
||||
|
||||
if (this.restartTimeout) clearTimeout(this.restartTimeout);
|
||||
|
||||
|
@ -137,7 +133,7 @@ export class RelayManager {
|
|||
});
|
||||
|
||||
if (this.process.stdout) {
|
||||
this.process.stdout.on("data", (data: Buffer) => {
|
||||
this.process.stdout.on('data', (data: Buffer) => {
|
||||
const logLine = data.toString().trim();
|
||||
this.addLog(logLine);
|
||||
console.log(logLine);
|
||||
|
@ -145,30 +141,26 @@ export class RelayManager {
|
|||
}
|
||||
|
||||
if (this.process.stderr) {
|
||||
this.process.stderr.on("data", (data: Buffer) => {
|
||||
this.process.stderr.on('data', (data: Buffer) => {
|
||||
const logLine = data.toString().trim();
|
||||
this.addLog(logLine);
|
||||
console.error(logLine);
|
||||
});
|
||||
}
|
||||
|
||||
this.process.on("error", (err: Error) => {
|
||||
this.process.on('error', (err: Error) => {
|
||||
console.error(`Failed to start Relay: ${err.message}`);
|
||||
this.process = null;
|
||||
this.restartProcess();
|
||||
});
|
||||
|
||||
this.process.on("exit", this.handleProcessExit.bind(this));
|
||||
this.process.on('exit', this.handleProcessExit.bind(this));
|
||||
|
||||
if (this.process.pid) {
|
||||
this.restartAttempts = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error starting Relay: ${
|
||||
error instanceof Error ? error.message : "Unknown error"
|
||||
}`
|
||||
);
|
||||
console.error(`Error starting Relay: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
this.restartProcess();
|
||||
}
|
||||
}
|
||||
|
|
32
src/main.ts
32
src/main.ts
|
@ -1,28 +1,28 @@
|
|||
import "./style.scss";
|
||||
import './style.scss';
|
||||
|
||||
import "@components/ErrorView";
|
||||
import "@components/NostrAvatar";
|
||||
import "@components/LoadingView";
|
||||
import "@components/NostrProfile";
|
||||
import "@components/Breadcrumbs";
|
||||
import "@components/Header";
|
||||
import "@routes/router";
|
||||
import "@components/LoadingView";
|
||||
import type EveRouter from "@routes/router";
|
||||
import { sleep } from "./utils/sleep";
|
||||
import '@components/ErrorView';
|
||||
import '@components/NostrAvatar';
|
||||
import '@components/LoadingView';
|
||||
import '@components/NostrProfile';
|
||||
import '@components/Breadcrumbs';
|
||||
import '@components/Header';
|
||||
import '@routes/router';
|
||||
import '@components/LoadingView';
|
||||
import type EveRouter from '@routes/router';
|
||||
import { sleep } from './utils/sleep';
|
||||
|
||||
async function startRelay() {
|
||||
if (localStorage.getItem("ncryptsec")) {
|
||||
const loadingIndicator = document.createElement("arx-loading-view");
|
||||
if (localStorage.getItem('ncryptsec')) {
|
||||
const loadingIndicator = document.createElement('arx-loading-view');
|
||||
document.body.appendChild(loadingIndicator);
|
||||
await window.relay.start(localStorage.getItem("encryption_key")!);
|
||||
await window.relay.start(localStorage.getItem('encryption_key')!);
|
||||
await sleep(5000);
|
||||
loadingIndicator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
startRelay().then(() => {
|
||||
const router = document.createElement("arx-eve-router") as EveRouter;
|
||||
router.ccnSetup = !!localStorage.getItem("ncryptsec");
|
||||
const router = document.createElement('arx-eve-router') as EveRouter;
|
||||
router.ccnSetup = !!localStorage.getItem('ncryptsec');
|
||||
document.body.appendChild(router);
|
||||
});
|
||||
|
|
22
src/ndk.ts
22
src/ndk.ts
|
@ -1,22 +1,20 @@
|
|||
import NDK, { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
||||
import * as nip49 from "@nostr/tools/nip49";
|
||||
import NDK, { NDKPrivateKeySigner } from '@nostr-dev-kit/ndk';
|
||||
import * as nip49 from '@nostr/tools/nip49';
|
||||
|
||||
export const ndk = new NDK({
|
||||
explicitRelayUrls: ["ws://localhost:6942"],
|
||||
explicitRelayUrls: ['ws://localhost:6942'],
|
||||
enableOutboxModel: false,
|
||||
autoConnectUserRelays: false,
|
||||
clientName: "Arx",
|
||||
clientNip89: "arx",
|
||||
clientName: 'Arx',
|
||||
clientNip89: 'arx',
|
||||
});
|
||||
|
||||
export async function getSigner() {
|
||||
await ndk.connect();
|
||||
if (ndk.signer) return;
|
||||
const encryptionPassphrase = localStorage.getItem("encryption_key");
|
||||
if (!encryptionPassphrase) throw new Error("Encryption passphrase not found");
|
||||
const signer = new NDKPrivateKeySigner(
|
||||
nip49.decrypt(localStorage.getItem("ncryptsec")!, encryptionPassphrase)
|
||||
);
|
||||
const encryptionPassphrase = localStorage.getItem('encryption_key');
|
||||
if (!encryptionPassphrase) throw new Error('Encryption passphrase not found');
|
||||
const signer = new NDKPrivateKeySigner(nip49.decrypt(localStorage.getItem('ncryptsec')!, encryptionPassphrase));
|
||||
setSigner(signer);
|
||||
}
|
||||
|
||||
|
@ -24,7 +22,7 @@ export async function getNpub() {
|
|||
await getSigner();
|
||||
const user = await ndk.signer?.user();
|
||||
if (user) return user.npub;
|
||||
throw new Error("Could not get npub");
|
||||
throw new Error('Could not get npub');
|
||||
}
|
||||
|
||||
export function setSigner(signer: NDKPrivateKeySigner) {
|
||||
|
@ -33,7 +31,7 @@ export function setSigner(signer: NDKPrivateKeySigner) {
|
|||
|
||||
export async function getUserProfile(npub: string) {
|
||||
await ndk.connect();
|
||||
const query = npub.startsWith("npub") ? { npub } : { pubkey: npub };
|
||||
const query = npub.startsWith('npub') ? { npub } : { pubkey: npub };
|
||||
const user = ndk.getUser(query);
|
||||
await user.fetchProfile();
|
||||
return user.profile;
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { html, css, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import type { RouteParams } from "./router";
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import type { RouteParams } from './router';
|
||||
|
||||
import "@components/EveLink";
|
||||
import '@components/EveLink';
|
||||
|
||||
@customElement("arx-404-page")
|
||||
@customElement('arx-404-page')
|
||||
export class FourOhFourPage extends LitElement {
|
||||
@property({ type: Object })
|
||||
params: RouteParams = {};
|
||||
|
||||
@property({ type: String })
|
||||
path = "";
|
||||
path = '';
|
||||
|
||||
@property({ type: Boolean })
|
||||
canGoBack = false;
|
||||
|
@ -177,10 +177,10 @@ export class FourOhFourPage extends LitElement {
|
|||
href="javascript:void(0)"
|
||||
@click="${() =>
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("go-back", {
|
||||
new CustomEvent('go-back', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
})
|
||||
}),
|
||||
)}"
|
||||
class="primary-button"
|
||||
>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { getNpub, getUserProfile } from "@/ndk";
|
||||
import type { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||
import { css, LitElement } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { html, literal } from "lit/static-html.js";
|
||||
import "@widgets/BitcoinBlockWidget";
|
||||
import "@components/AppGrid";
|
||||
import { getNpub, getUserProfile } from '@/ndk';
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { LitElement, css } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { html, literal } from 'lit/static-html.js';
|
||||
import '@widgets/BitcoinBlockWidget';
|
||||
import '@components/AppGrid';
|
||||
|
||||
@customElement("arx-eve-home")
|
||||
@customElement('arx-eve-home')
|
||||
export class Home extends LitElement {
|
||||
@state()
|
||||
private npub: string | undefined;
|
||||
|
@ -18,72 +18,72 @@ export class Home extends LitElement {
|
|||
apps = [
|
||||
{
|
||||
id: 0,
|
||||
href: "letters",
|
||||
name: "Letters",
|
||||
color: "#FF33BB",
|
||||
icon: "bxs:envelope",
|
||||
href: 'letters',
|
||||
name: 'Letters',
|
||||
color: '#FF33BB',
|
||||
icon: 'bxs:envelope',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
href: "messages",
|
||||
name: "Messages",
|
||||
color: "#34C759",
|
||||
icon: "bxs:chat",
|
||||
href: 'messages',
|
||||
name: 'Messages',
|
||||
color: '#34C759',
|
||||
icon: 'bxs:chat',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
href: "calendar",
|
||||
name: "Calendar",
|
||||
color: "#FF9500",
|
||||
icon: "bxs:calendar",
|
||||
href: 'calendar',
|
||||
name: 'Calendar',
|
||||
color: '#FF9500',
|
||||
icon: 'bxs:calendar',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
href: "phora",
|
||||
name: "Phora",
|
||||
color: "#FF3B30",
|
||||
icon: "bxs:conversation",
|
||||
href: 'phora',
|
||||
name: 'Phora',
|
||||
color: '#FF3B30',
|
||||
icon: 'bxs:conversation',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
href: "agora",
|
||||
name: "Agora",
|
||||
color: "#5856D6",
|
||||
icon: "bxs:store",
|
||||
href: 'agora',
|
||||
name: 'Agora',
|
||||
color: '#5856D6',
|
||||
icon: 'bxs:store',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
href: "wallet",
|
||||
name: "Wallet",
|
||||
color: "#007AFF",
|
||||
icon: "bxs:wallet",
|
||||
href: 'wallet',
|
||||
name: 'Wallet',
|
||||
color: '#007AFF',
|
||||
icon: 'bxs:wallet',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
href: "consortium",
|
||||
name: "Consortium",
|
||||
color: "#FFCC00",
|
||||
icon: "bxs:landmark",
|
||||
href: 'consortium',
|
||||
name: 'Consortium',
|
||||
color: '#FFCC00',
|
||||
icon: 'bxs:landmark',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
href: "settings",
|
||||
name: "Settings",
|
||||
color: "#deadbeef",
|
||||
icon: "bxs:wrench",
|
||||
href: 'settings',
|
||||
name: 'Settings',
|
||||
color: '#deadbeef',
|
||||
icon: 'bxs:wrench',
|
||||
},
|
||||
];
|
||||
|
||||
widgets = [
|
||||
{
|
||||
title: "Bitcoin Block",
|
||||
title: 'Bitcoin Block',
|
||||
content: literal`arx-bitcoin-block-widget`,
|
||||
},
|
||||
];
|
||||
|
||||
async loadProperties() {
|
||||
const npub = await getNpub();
|
||||
if (!npub) return alert("No npub?");
|
||||
if (!npub) return alert('No npub?');
|
||||
this.npub = npub;
|
||||
this.profile = (await getUserProfile(this.npub)) as NDKUserProfile;
|
||||
this.username = this.profile?.name || this.npub.substring(0, 8);
|
||||
|
@ -242,7 +242,7 @@ export class Home extends LitElement {
|
|||
<h3>${widget.title}</h3>
|
||||
<${widget.content}></${widget.content}>
|
||||
</div>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { getSigner, ndk } from "@/ndk";
|
||||
import formatDateTime from "@utils/formatDateTime";
|
||||
import type { NDKSubscription } from "@nostr-dev-kit/ndk";
|
||||
import { getSigner, ndk } from '@/ndk';
|
||||
import type { NDKSubscription } from '@nostr-dev-kit/ndk';
|
||||
import formatDateTime from '@utils/formatDateTime';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
|
||||
import "@components/Breadcrumbs";
|
||||
import "@components/PhoraForumCategory";
|
||||
import "@components/PhoraForumTopic";
|
||||
import "@components/PhoraButton";
|
||||
import '@components/Breadcrumbs';
|
||||
import '@components/PhoraForumCategory';
|
||||
import '@components/PhoraForumTopic';
|
||||
import '@components/PhoraButton';
|
||||
|
||||
interface ForumTopic {
|
||||
id: string;
|
||||
|
@ -24,7 +24,7 @@ interface ForumCategory {
|
|||
topics: ForumTopic[];
|
||||
}
|
||||
|
||||
@customElement("arx-phora-home")
|
||||
@customElement('arx-phora-home')
|
||||
export class PhoraForum extends LitElement {
|
||||
@state()
|
||||
private categories: ForumCategory[] = [];
|
||||
|
@ -53,18 +53,14 @@ export class PhoraForum extends LitElement {
|
|||
.subscribe({
|
||||
kinds: [11],
|
||||
})
|
||||
.on("event", (event) => {
|
||||
const subject = event.tags.find(
|
||||
(tag: string[]) => tag[0] === "subject"
|
||||
);
|
||||
const parent = event.tags.find((tag: string[]) => tag[0] === "e");
|
||||
.on('event', (event) => {
|
||||
const subject = event.tags.find((tag: string[]) => tag[0] === 'subject');
|
||||
const parent = event.tags.find((tag: string[]) => tag[0] === 'e');
|
||||
|
||||
if (!subject) return;
|
||||
|
||||
if (parent) {
|
||||
const categoryIndex = this.categories.findIndex(
|
||||
(category) => category.id === parent[1]
|
||||
);
|
||||
const categoryIndex = this.categories.findIndex((category) => category.id === parent[1]);
|
||||
if (categoryIndex === -1) return;
|
||||
|
||||
const updatedCategories = [...this.categories];
|
||||
|
@ -95,7 +91,7 @@ export class PhoraForum extends LitElement {
|
|||
override render() {
|
||||
return html`
|
||||
<arx-breadcrumbs
|
||||
.items=${[{ text: "Home", href: "/" }, { text: "Phora" }]}
|
||||
.items=${[{ text: 'Home', href: '/' }, { text: 'Phora' }]}
|
||||
>
|
||||
</arx-breadcrumbs>
|
||||
|
||||
|
@ -116,10 +112,10 @@ export class PhoraForum extends LitElement {
|
|||
lastPostTime=${topic.created_at}
|
||||
>
|
||||
</arx-phora-forum-topic>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</arx-phora-forum-category>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { getSigner, ndk } from "@/ndk";
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
import { getSigner, ndk } from '@/ndk';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-phora-category-creator")
|
||||
@customElement('arx-phora-category-creator')
|
||||
export class PhoraCategoryCreator extends LitElement {
|
||||
@state()
|
||||
private newCategory = "";
|
||||
private newCategory = '';
|
||||
|
||||
@state()
|
||||
private categoryDescription = "";
|
||||
private categoryDescription = '';
|
||||
|
||||
static override styles = css`
|
||||
:host {
|
||||
|
@ -33,12 +33,12 @@ export class PhoraCategoryCreator extends LitElement {
|
|||
|
||||
private async doCreateCategory() {
|
||||
if (this.newCategory.length < 3) {
|
||||
alert("Category name must be at least 3 characters long");
|
||||
alert('Category name must be at least 3 characters long');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.categoryDescription.length < 10) {
|
||||
alert("Category description must be at least 10 characters long");
|
||||
alert('Category description must be at least 10 characters long');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -46,23 +46,23 @@ export class PhoraCategoryCreator extends LitElement {
|
|||
await getSigner();
|
||||
const event = new NDKEvent(ndk);
|
||||
event.kind = 11;
|
||||
event.tags = [["subject", this.newCategory]];
|
||||
event.tags = [['subject', this.newCategory]];
|
||||
event.content = this.categoryDescription;
|
||||
await event.sign();
|
||||
await event.publish();
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("category-created", {
|
||||
new CustomEvent('category-created', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
this.newCategory = "";
|
||||
this.categoryDescription = "";
|
||||
this.newCategory = '';
|
||||
this.categoryDescription = '';
|
||||
} catch (error) {
|
||||
console.error("Failed to create category:", error);
|
||||
alert("Failed to create category");
|
||||
console.error('Failed to create category:', error);
|
||||
alert('Failed to create category');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { getSigner, ndk } from "@/ndk";
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
import { getSigner, ndk } from '@/ndk';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-phora-post-creator")
|
||||
@customElement('arx-phora-post-creator')
|
||||
export class PhoraPostCreator extends LitElement {
|
||||
@property({ type: String })
|
||||
topicId = "";
|
||||
topicId = '';
|
||||
|
||||
@state()
|
||||
private postContent = "";
|
||||
private postContent = '';
|
||||
|
||||
@state()
|
||||
private isCreating = false;
|
||||
|
@ -71,7 +71,7 @@ export class PhoraPostCreator extends LitElement {
|
|||
if (this.isCreating) return;
|
||||
|
||||
if (this.postContent.length < 10) {
|
||||
this.error = "Post content must be at least 10 characters long";
|
||||
this.error = 'Post content must be at least 10 characters long';
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -82,27 +82,27 @@ export class PhoraPostCreator extends LitElement {
|
|||
await getSigner();
|
||||
const event = new NDKEvent(ndk);
|
||||
event.kind = 1111;
|
||||
event.tags = [["e", this.topicId]];
|
||||
event.tags = [['e', this.topicId]];
|
||||
event.content = this.postContent;
|
||||
await event.sign();
|
||||
await event.publish();
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("post-created", {
|
||||
new CustomEvent('post-created', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
postId: event.id,
|
||||
topicId: this.topicId,
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Reset form
|
||||
this.postContent = "";
|
||||
this.postContent = '';
|
||||
} catch (error) {
|
||||
console.error("Failed to create post:", error);
|
||||
this.error = "Failed to create post. Please try again.";
|
||||
console.error('Failed to create post:', error);
|
||||
this.error = 'Failed to create post. Please try again.';
|
||||
} finally {
|
||||
this.isCreating = false;
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ export class PhoraPostCreator extends LitElement {
|
|||
|
||||
<div class="actions">
|
||||
<arx-phora-button
|
||||
@click=${() => this.dispatchEvent(new CustomEvent("cancel"))}
|
||||
@click=${() => this.dispatchEvent(new CustomEvent('cancel'))}
|
||||
?disabled=${this.isCreating}
|
||||
>
|
||||
Cancel
|
||||
|
@ -141,7 +141,7 @@ export class PhoraPostCreator extends LitElement {
|
|||
@click=${this.doCreatePost}
|
||||
?disabled=${this.isCreating}
|
||||
>
|
||||
${this.isCreating ? "Creating..." : "Create"}
|
||||
${this.isCreating ? 'Creating...' : 'Create'}
|
||||
</arx-phora-button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { getSigner, ndk } from "@/ndk";
|
||||
import { NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
import { getSigner, ndk } from '@/ndk';
|
||||
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
@customElement("arx-phora-topic-creator")
|
||||
@customElement('arx-phora-topic-creator')
|
||||
export class PhoraTopicCreator extends LitElement {
|
||||
@property({ type: String })
|
||||
categoryId = "";
|
||||
categoryId = '';
|
||||
|
||||
@state()
|
||||
private newTopic = "";
|
||||
private newTopic = '';
|
||||
|
||||
@state()
|
||||
private topicContent = "";
|
||||
private topicContent = '';
|
||||
|
||||
@state()
|
||||
private isCreating = false;
|
||||
|
@ -52,12 +52,12 @@ export class PhoraTopicCreator extends LitElement {
|
|||
if (this.isCreating) return;
|
||||
|
||||
if (this.newTopic.length < 3) {
|
||||
alert("Topic title must be at least 3 characters long");
|
||||
alert('Topic title must be at least 3 characters long');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.topicContent.length < 10) {
|
||||
alert("Topic content must be at least 10 characters long");
|
||||
alert('Topic content must be at least 10 characters long');
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -68,29 +68,29 @@ export class PhoraTopicCreator extends LitElement {
|
|||
const event = new NDKEvent(ndk);
|
||||
event.kind = 11;
|
||||
event.tags = [
|
||||
["subject", this.newTopic],
|
||||
["e", this.categoryId],
|
||||
['subject', this.newTopic],
|
||||
['e', this.categoryId],
|
||||
];
|
||||
event.content = this.topicContent;
|
||||
await event.sign();
|
||||
await event.publish();
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("topic-created", {
|
||||
new CustomEvent('topic-created', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
topicId: event.id,
|
||||
categoryId: this.categoryId,
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
this.newTopic = "";
|
||||
this.topicContent = "";
|
||||
this.newTopic = '';
|
||||
this.topicContent = '';
|
||||
} catch (error) {
|
||||
console.error("Failed to create topic:", error);
|
||||
alert("Failed to create topic");
|
||||
console.error('Failed to create topic:', error);
|
||||
alert('Failed to create topic');
|
||||
} finally {
|
||||
this.isCreating = false;
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ export class PhoraTopicCreator extends LitElement {
|
|||
|
||||
<div class="button-group">
|
||||
<arx-phora-button
|
||||
@click=${() => this.dispatchEvent(new CustomEvent("cancel"))}
|
||||
@click=${() => this.dispatchEvent(new CustomEvent('cancel'))}
|
||||
?disabled=${this.isCreating}
|
||||
>
|
||||
Cancel
|
||||
|
@ -135,7 +135,7 @@ export class PhoraTopicCreator extends LitElement {
|
|||
@click=${this.doCreateTopic}
|
||||
?disabled=${this.isCreating}
|
||||
>
|
||||
${this.isCreating ? "Creating..." : "Create"}
|
||||
${this.isCreating ? 'Creating...' : 'Create'}
|
||||
</arx-phora-button>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { getSigner, ndk } from "@/ndk";
|
||||
import type { NDKSubscription } from "@nostr-dev-kit/ndk";
|
||||
import { getSigner, ndk } from '@/ndk';
|
||||
import type { NDKSubscription } from '@nostr-dev-kit/ndk';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
|
||||
import "@components/Breadcrumbs";
|
||||
import "@components/ForumPost";
|
||||
import "@components/PhoraButton";
|
||||
import '@components/Breadcrumbs';
|
||||
import '@components/ForumPost';
|
||||
import '@components/PhoraButton';
|
||||
|
||||
interface ForumPost {
|
||||
id: string;
|
||||
|
@ -14,13 +14,13 @@ interface ForumPost {
|
|||
content: string;
|
||||
}
|
||||
|
||||
@customElement("arx-phora-topic-view")
|
||||
@customElement('arx-phora-topic-view')
|
||||
export class PhoraTopicView extends LitElement {
|
||||
@property({ type: String })
|
||||
topicId = "";
|
||||
topicId = '';
|
||||
|
||||
@state()
|
||||
override title = "";
|
||||
override title = '';
|
||||
|
||||
@state()
|
||||
private posts: ForumPost[] = [];
|
||||
|
@ -82,10 +82,10 @@ export class PhoraTopicView extends LitElement {
|
|||
const event = await ndk.fetchEvent(this.topicId);
|
||||
|
||||
if (!event) {
|
||||
throw new Error("Could not load topic");
|
||||
throw new Error('Could not load topic');
|
||||
}
|
||||
|
||||
this.title = event.tags.find((tag) => tag[0] === "subject")?.[1] || "";
|
||||
this.title = event.tags.find((tag) => tag[0] === 'subject')?.[1] || '';
|
||||
|
||||
this.posts = [
|
||||
{
|
||||
|
@ -100,9 +100,9 @@ export class PhoraTopicView extends LitElement {
|
|||
this.subscription = ndk
|
||||
.subscribe({
|
||||
kinds: [1111],
|
||||
"#e": [this.topicId],
|
||||
'#e': [this.topicId],
|
||||
})
|
||||
.on("event", (event) => {
|
||||
.on('event', (event) => {
|
||||
this.posts = [
|
||||
...this.posts,
|
||||
{
|
||||
|
@ -114,17 +114,13 @@ export class PhoraTopicView extends LitElement {
|
|||
];
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to load topic:", error);
|
||||
alert("Could not load topic");
|
||||
console.error('Failed to load topic:', error);
|
||||
alert('Could not load topic');
|
||||
}
|
||||
}
|
||||
|
||||
override render() {
|
||||
const breadcrumbItems = [
|
||||
{ text: "Home", href: "/" },
|
||||
{ text: "Phora", href: "/phora" },
|
||||
{ text: this.title },
|
||||
];
|
||||
const breadcrumbItems = [{ text: 'Home', href: '/' }, { text: 'Phora', href: '/phora' }, { text: this.title }];
|
||||
|
||||
return html`
|
||||
<arx-breadcrumbs .items=${breadcrumbItems}></arx-breadcrumbs>
|
||||
|
@ -144,7 +140,7 @@ export class PhoraTopicView extends LitElement {
|
|||
.date=${post.date}
|
||||
.content=${post.content}
|
||||
></arx-forum-post>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { LitElement, html, css } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { when } from "lit/directives/when.js";
|
||||
import type { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||
import { getUserProfile } from "../ndk";
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
import { LitElement, css, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { when } from 'lit/directives/when.js';
|
||||
import { getUserProfile } from '../ndk';
|
||||
|
||||
@customElement("arx-profile-route")
|
||||
@customElement('arx-profile-route')
|
||||
export class NostrProfile extends LitElement {
|
||||
@property({ type: String })
|
||||
npub = "";
|
||||
npub = '';
|
||||
|
||||
@state()
|
||||
private profile: NDKUserProfile | undefined;
|
||||
|
@ -282,16 +282,14 @@ export class NostrProfile extends LitElement {
|
|||
try {
|
||||
this.profile = await getUserProfile(this.npub);
|
||||
} catch (err) {
|
||||
this.error = "Failed to load profile";
|
||||
this.error = 'Failed to load profile';
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
private get displayName() {
|
||||
if (!this.profile) return this.npub;
|
||||
return (
|
||||
this.profile.displayName || this.profile.name || this.npub.substring(0, 8)
|
||||
);
|
||||
return this.profile.displayName || this.profile.name || this.npub.substring(0, 8);
|
||||
}
|
||||
|
||||
override render() {
|
||||
|
@ -313,13 +311,11 @@ export class NostrProfile extends LitElement {
|
|||
</div>
|
||||
<div class="banner-overlay"></div>
|
||||
</div>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
|
||||
<div
|
||||
class=${this.profile.banner
|
||||
? "profile-container with-banner"
|
||||
: "profile-container no-banner"}
|
||||
class=${this.profile.banner ? 'profile-container with-banner' : 'profile-container no-banner'}
|
||||
>
|
||||
<div class="profile-card">
|
||||
<div class="profile-content">
|
||||
|
@ -339,7 +335,7 @@ export class NostrProfile extends LitElement {
|
|||
class="placeholder-icon"
|
||||
></svg-icon>
|
||||
</div>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
@ -354,7 +350,7 @@ export class NostrProfile extends LitElement {
|
|||
<span class="verified-icon">
|
||||
<svg-icon icon="mdi:check-decagram"></svg-icon>
|
||||
</span>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</h1>
|
||||
${when(
|
||||
|
@ -364,15 +360,12 @@ export class NostrProfile extends LitElement {
|
|||
<svg-icon icon="mdi:at"></svg-icon>
|
||||
${this.profile!.nip05}
|
||||
</p>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${when(
|
||||
this.profile.about,
|
||||
() => html` <p class="bio">${this.profile!.about}</p> `
|
||||
)}
|
||||
${when(this.profile.about, () => html` <p class="bio">${this.profile!.about}</p> `)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -388,7 +381,7 @@ export class NostrProfile extends LitElement {
|
|||
<svg-icon icon="mdi:web" class="link-icon website"></svg-icon>
|
||||
<span>${this.profile!.website}</span>
|
||||
</a>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
${when(
|
||||
this.profile.lud16,
|
||||
|
@ -400,7 +393,7 @@ export class NostrProfile extends LitElement {
|
|||
></svg-icon>
|
||||
<span>${this.profile!.lud16}</span>
|
||||
</a>
|
||||
`
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import "@routes/404Page";
|
||||
import "@routes/Home";
|
||||
import "@routes/Profile";
|
||||
import "@routes/Phora/Home";
|
||||
import "@routes/Phora/NewCategory";
|
||||
import "@routes/Phora/NewTopic";
|
||||
import "@routes/Phora/TopicView";
|
||||
import "@routes/Phora/NewPost";
|
||||
import "@components/InitialSetup";
|
||||
import '@routes/404Page';
|
||||
import '@routes/Home';
|
||||
import '@routes/Profile';
|
||||
import '@routes/Phora/Home';
|
||||
import '@routes/Phora/NewCategory';
|
||||
import '@routes/Phora/NewTopic';
|
||||
import '@routes/Phora/TopicView';
|
||||
import '@routes/Phora/NewPost';
|
||||
import '@components/InitialSetup';
|
||||
|
||||
import { css, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { html, literal, type StaticValue } from "lit/static-html.js";
|
||||
import { spread } from "@open-wc/lit-helpers";
|
||||
import { spread } from '@open-wc/lit-helpers';
|
||||
import { LitElement, css } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { type StaticValue, html, literal } from 'lit/static-html.js';
|
||||
|
||||
export interface RouteParams {
|
||||
[key: string]: string;
|
||||
|
@ -26,46 +26,46 @@ interface Route {
|
|||
meta?: Record<string, string>;
|
||||
}
|
||||
|
||||
@customElement("arx-eve-router")
|
||||
@customElement('arx-eve-router')
|
||||
export default class EveRouter extends LitElement {
|
||||
private static routes: Route[] = [
|
||||
{
|
||||
pattern: "home",
|
||||
pattern: 'home',
|
||||
params: {},
|
||||
component: literal`arx-eve-home`,
|
||||
},
|
||||
{
|
||||
pattern: "profile/:npub",
|
||||
pattern: 'profile/:npub',
|
||||
params: {},
|
||||
component: literal`arx-profile-route`,
|
||||
},
|
||||
{
|
||||
pattern: "phora",
|
||||
pattern: 'phora',
|
||||
params: {},
|
||||
component: literal`arx-phora-home`,
|
||||
},
|
||||
{
|
||||
pattern: "phora/new-category",
|
||||
pattern: 'phora/new-category',
|
||||
params: {},
|
||||
component: literal`arx-phora-category-creator`,
|
||||
},
|
||||
{
|
||||
pattern: "phora/new-topic/:categoryId",
|
||||
pattern: 'phora/new-topic/:categoryId',
|
||||
params: {},
|
||||
component: literal`arx-phora-topic-creator`,
|
||||
},
|
||||
{
|
||||
pattern: "phora/topics/:topicId",
|
||||
pattern: 'phora/topics/:topicId',
|
||||
params: {},
|
||||
component: literal`arx-phora-topic-view`,
|
||||
},
|
||||
{
|
||||
pattern: "phora/new-post/:topicId",
|
||||
pattern: 'phora/new-post/:topicId',
|
||||
params: {},
|
||||
component: literal`arx-phora-post-creator`,
|
||||
},
|
||||
{
|
||||
pattern: "404",
|
||||
pattern: '404',
|
||||
params: {},
|
||||
component: literal`arx-404-page`,
|
||||
},
|
||||
|
@ -116,8 +116,7 @@ export default class EveRouter extends LitElement {
|
|||
constructor() {
|
||||
super();
|
||||
this.initializeRouter();
|
||||
if (this.ccnSetup)
|
||||
window.relay.start(localStorage.getItem("encryption_key")!);
|
||||
if (this.ccnSetup) window.relay.start(localStorage.getItem('encryption_key')!);
|
||||
}
|
||||
|
||||
override connectedCallback(): void {
|
||||
|
@ -127,8 +126,8 @@ export default class EveRouter extends LitElement {
|
|||
|
||||
override disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener("hashchange", this.handleHashChange);
|
||||
window.removeEventListener("popstate", this.handlePopState);
|
||||
window.removeEventListener('hashchange', this.handleHashChange);
|
||||
window.removeEventListener('popstate', this.handlePopState);
|
||||
}
|
||||
|
||||
private initializeRouter(): void {
|
||||
|
@ -139,8 +138,8 @@ export default class EveRouter extends LitElement {
|
|||
}
|
||||
|
||||
private setupEventListeners(): void {
|
||||
window.addEventListener("hashchange", this.handleHashChange.bind(this));
|
||||
window.addEventListener("popstate", this.handlePopState.bind(this));
|
||||
window.addEventListener('hashchange', this.handleHashChange.bind(this));
|
||||
window.addEventListener('popstate', this.handlePopState.bind(this));
|
||||
}
|
||||
|
||||
private handleHashChange(): void {
|
||||
|
@ -161,12 +160,9 @@ export default class EveRouter extends LitElement {
|
|||
this.currentIndex = this.history.length - 1;
|
||||
}
|
||||
|
||||
private matchRoute(
|
||||
pattern: string,
|
||||
path: string
|
||||
): { isMatch: boolean; params: RouteParams } {
|
||||
const patternParts = pattern.split("/").filter(Boolean);
|
||||
const pathParts = path.split("/").filter(Boolean);
|
||||
private matchRoute(pattern: string, path: string): { isMatch: boolean; params: RouteParams } {
|
||||
const patternParts = pattern.split('/').filter(Boolean);
|
||||
const pathParts = path.split('/').filter(Boolean);
|
||||
const params: RouteParams = {};
|
||||
|
||||
if (patternParts.length !== pathParts.length) {
|
||||
|
@ -175,7 +171,7 @@ export default class EveRouter extends LitElement {
|
|||
|
||||
const isMatch = patternParts.every((patternPart, index) => {
|
||||
const pathPart = pathParts[index];
|
||||
if (patternPart.startsWith(":")) {
|
||||
if (patternPart.startsWith(':')) {
|
||||
const paramName = patternPart.slice(1);
|
||||
params[paramName] = decodeURIComponent(pathPart);
|
||||
return true;
|
||||
|
@ -188,15 +184,12 @@ export default class EveRouter extends LitElement {
|
|||
|
||||
get currentPath(): string {
|
||||
const hash = window.location.hash?.slice(1);
|
||||
return hash === "" ? "home" : hash;
|
||||
return hash === '' ? 'home' : hash;
|
||||
}
|
||||
|
||||
get currentRoute(): Route {
|
||||
const route = EveRouter.routes.find((route) => {
|
||||
const { isMatch, params } = this.matchRoute(
|
||||
route.pattern,
|
||||
this.currentPath
|
||||
);
|
||||
const { isMatch, params } = this.matchRoute(route.pattern, this.currentPath);
|
||||
if (isMatch) {
|
||||
route.params = params;
|
||||
return true;
|
||||
|
@ -208,7 +201,7 @@ export default class EveRouter extends LitElement {
|
|||
|
||||
private getNotFoundRoute(): Route {
|
||||
return {
|
||||
pattern: "404",
|
||||
pattern: '404',
|
||||
params: {},
|
||||
component: literal`arx-404-page`,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||
import type { NDKUserProfile } from '@nostr-dev-kit/ndk';
|
||||
|
||||
interface ProfileProps {
|
||||
profile: NDKUserProfile;
|
||||
|
|
|
@ -14,7 +14,7 @@ function formatSatsGroup(sats: number): string {
|
|||
.join('')
|
||||
.match(/.{1,3}/g)
|
||||
?.reverse()
|
||||
.map(group => group.split('').reverse().join(''))
|
||||
.map((group) => group.split('').reverse().join(''))
|
||||
.join(' ') || '0'
|
||||
);
|
||||
}
|
||||
|
@ -29,10 +29,7 @@ function formatBtcGroup(sats: number): string {
|
|||
?.join(' ')} BTC`.trim();
|
||||
}
|
||||
|
||||
export default function satsComma(
|
||||
sats: number,
|
||||
format: SatcommaFormat = SatcommaFormat.SATS,
|
||||
): string {
|
||||
export default function satsComma(sats: number, format: SatcommaFormat = SatcommaFormat.SATS): string {
|
||||
if (!Number.isFinite(sats)) {
|
||||
throw new Error('Invalid input: sats must be a finite number');
|
||||
}
|
||||
|
@ -41,7 +38,5 @@ export default function satsComma(
|
|||
return `-${satsComma(Math.abs(sats), format)}`;
|
||||
}
|
||||
|
||||
return format === SatcommaFormat.SATS
|
||||
? formatSatsGroup(sats)
|
||||
: formatBtcGroup(sats);
|
||||
return format === SatcommaFormat.SATS ? formatSatsGroup(sats) : formatBtcGroup(sats);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue