201 lines
6.2 KiB
TypeScript
201 lines
6.2 KiB
TypeScript
import defaultAvatar from '@/default-avatar.png';
|
|
import { getSigner, getUserProfile, ndk } from '@/ndk';
|
|
import type { ArxInputChangeEvent } from '@components/General/Input';
|
|
import { NDKEvent, type NDKUserProfile } from '@nostr-dev-kit/ndk';
|
|
import { LitElement, css, html } from 'lit';
|
|
import { customElement, state } from 'lit/decorators.js';
|
|
import { when } from 'lit/directives/when.js';
|
|
|
|
import '@components/Breadcrumbs';
|
|
import '@components/DateTimeSettings';
|
|
import '@components/General/Button';
|
|
import '@components/General/Card';
|
|
import '@components/General/Fieldset';
|
|
import '@components/General/Input';
|
|
import '@components/RelayLogs';
|
|
|
|
@customElement('arx-settings')
|
|
export class EveSettings extends LitElement {
|
|
static override styles = css`
|
|
:host {
|
|
display: block;
|
|
font-family: var(--font-family, "Inter", system-ui, sans-serif);
|
|
margin: 0 auto;
|
|
line-height: 1.6;
|
|
color: var(--color-base-content);
|
|
background-color: var(--color-base-100);
|
|
}
|
|
|
|
.profile-image {
|
|
width: 140px;
|
|
height: 140px;
|
|
border-radius: 50%;
|
|
object-fit: cover;
|
|
border: calc(var(--border) * 2) solid var(--color-base-100);
|
|
box-shadow: calc(var(--depth) * 3px) calc(var(--depth) * 3px)
|
|
calc(var(--depth) * 6px)
|
|
oklch(from var(--color-base-content) l c h / 0.15),
|
|
calc(var(--depth) * -2px) calc(var(--depth) * -2px)
|
|
calc(var(--depth) * 4px) oklch(from var(--color-base-100) l c h / 0.6);
|
|
transition: transform 0.3s, box-shadow 0.3s;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.profile-image:hover {
|
|
transform: scale(1.05);
|
|
box-shadow: calc(var(--depth) * 4px) calc(var(--depth) * 4px)
|
|
calc(var(--depth) * 8px) oklch(from var(--color-accent) l c h / 0.3),
|
|
calc(var(--depth) * -2px) calc(var(--depth) * -2px)
|
|
calc(var(--depth) * 6px) oklch(from var(--color-base-100) l c h / 0.6);
|
|
}
|
|
|
|
.profile-header {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
`;
|
|
|
|
@state() private loading = true;
|
|
@state() private saving = false;
|
|
@state() private profile: NDKUserProfile | undefined;
|
|
@state() private error: string | undefined;
|
|
@state() private darkMode = false;
|
|
@state() private relayStatus: { running: boolean; pid: number | null; logs: string[] } = {
|
|
running: false,
|
|
pid: null,
|
|
logs: [],
|
|
};
|
|
|
|
private async updateRelayStatus() {
|
|
this.relayStatus = await window.relay.getStatus();
|
|
if (this.relayStatus.running) setTimeout(() => this.updateRelayStatus(), 2000);
|
|
}
|
|
|
|
protected override async firstUpdated() {
|
|
try {
|
|
this.profile = await getUserProfile();
|
|
this.darkMode = localStorage.getItem('darkMode') === 'true';
|
|
this.updateRelayStatus();
|
|
this.loading = false;
|
|
} catch (err) {
|
|
this.error = 'Failed to load profile';
|
|
console.error(err);
|
|
this.loading = false;
|
|
}
|
|
}
|
|
|
|
private handleInputChange(field: string, e: ArxInputChangeEvent) {
|
|
this.profile = {
|
|
...this.profile,
|
|
[field]: e.detail.value,
|
|
};
|
|
}
|
|
|
|
private async saveProfile() {
|
|
if (this.saving) return;
|
|
this.saving = true;
|
|
try {
|
|
await getSigner();
|
|
const event = new NDKEvent(ndk);
|
|
event.kind = 0;
|
|
event.content = JSON.stringify(this.profile);
|
|
await event.sign();
|
|
await event.publish();
|
|
} catch (err) {
|
|
alert(err);
|
|
console.error(err);
|
|
} finally {
|
|
this.saving = false;
|
|
}
|
|
}
|
|
|
|
private toggleDarkMode() {
|
|
this.darkMode = !this.darkMode;
|
|
localStorage.setItem('darkMode', this.darkMode.toString());
|
|
document.body.classList.toggle('dark', this.darkMode);
|
|
}
|
|
|
|
override render() {
|
|
if (this.error) return html`<arx-error-view .error=${this.error}></arx-error-view>`;
|
|
|
|
if (this.loading) return html`<arx-loading-view></arx-loading-view>`;
|
|
|
|
const breadcrumbItems = [{ text: 'Home', href: '/' }, { text: 'Settings' }];
|
|
|
|
return html`
|
|
<arx-breadcrumbs .items=${breadcrumbItems}></arx-breadcrumbs>
|
|
<arx-card>
|
|
<arx-fieldset legend="Dark Mode">
|
|
<arx-toggle
|
|
label="Dark Mode"
|
|
.checked=${this.darkMode}
|
|
@change=${() => this.toggleDarkMode()}
|
|
></arx-toggle>
|
|
</arx-fieldset>
|
|
<arx-fieldset legend="Profile">
|
|
${when(
|
|
this.profile!.picture,
|
|
() => html`
|
|
<div class="profile-header">
|
|
<img
|
|
class="profile-image"
|
|
src=${this.profile!.picture}
|
|
alt="Profile"
|
|
@error=${(e: Event) => {
|
|
(e.target as HTMLImageElement).src = defaultAvatar;
|
|
}}
|
|
/>
|
|
</div>
|
|
`,
|
|
)}
|
|
|
|
<arx-input
|
|
label="Name"
|
|
type="text"
|
|
name="name"
|
|
.value=${this.profile!.name}
|
|
@change=${(e: ArxInputChangeEvent) => this.handleInputChange('name', e)}
|
|
placeholder="Your display name"
|
|
></arx-input>
|
|
|
|
<arx-input
|
|
label="Profile Image URL"
|
|
type="text"
|
|
name="image"
|
|
.value=${this.profile!.picture}
|
|
@change=${(e: ArxInputChangeEvent) => this.handleInputChange('picture', e)}
|
|
placeholder="https://example.com/your-image.jpg"
|
|
></arx-input>
|
|
|
|
<arx-input
|
|
label="Banner URL"
|
|
type="text"
|
|
name="banner"
|
|
.value=${this.profile!.banner}
|
|
@change=${(e: ArxInputChangeEvent) => this.handleInputChange('banner', e)}
|
|
placeholder="https://example.com/your-image.jpg"
|
|
></arx-input>
|
|
</arx-fieldset>
|
|
|
|
<arx-date-time-settings></arx-date-time-settings>
|
|
|
|
<arx-button
|
|
.label=${this.saving ? 'Saving...' : 'Save Changes'}
|
|
@click=${this.saveProfile}
|
|
?disabled=${this.saving}
|
|
>
|
|
</arx-button>
|
|
</arx-card>
|
|
<arx-card>
|
|
<arx-fieldset legend="Relay">
|
|
<p>
|
|
${this.relayStatus.running ? `Relay is running. PID: ${this.relayStatus.pid}` : 'Relay is not running'}
|
|
</p>
|
|
<arx-relay-logs .logs=${this.relayStatus.logs}></arx-relay-logs>
|
|
</arx-fieldset>
|
|
</arx-card>
|
|
`;
|
|
}
|
|
}
|