From ded004ffc24f887fde3b58efd4e48945e79dc30d Mon Sep 17 00:00:00 2001 From: Yusuke Ohashi Date: Fri, 13 Mar 2026 18:29:00 +0900 Subject: [PATCH 1/2] Apply nox night theme - Rename noxtr to nox and simplify UI copy --- README.md | 4 +- package.json | 4 +- src/common/meta.ts | 2 +- src/common/navigation.ts | 18 + src/features/about/about-page.ts | 14 +- src/features/home/welcome.ts | 89 ++- src/features/relays/relays-page.ts | 2 +- src/index.html | 101 ++-- src/styles.css | 863 +++++++++++++++++++++++++++++ 9 files changed, 1025 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index e6856c0..c8caccd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# noxtr +# nox -Nostr SPA built with TypeScript + Vite. +nox is a relay-first SPA built with TypeScript + Vite. This README is for developers working on this repository. ## Stack diff --git a/package.json b/package.json index ad37ec5..65a2b4f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "nostr-spa", + "name": "nox", "version": "1.0.0", - "description": "Simple Nostr SPA", + "description": "nox relay-first client", "type": "module", "scripts": { "dev": "vite", diff --git a/src/common/meta.ts b/src/common/meta.ts index 88db1e0..c771831 100644 --- a/src/common/meta.ts +++ b/src/common/meta.ts @@ -49,7 +49,7 @@ export function setEventMeta( event: { id: string; content: string; created_at: number; pubkey: string }, npub: Npub, ): void { - const title: string = `noxtr - Event ${event.id.slice(0, 8)}`; + const title: string = `nox - Event ${event.id.slice(0, 8)}`; const description: string = event.content.length > 140 ? `${event.content.slice(0, 140)}...` diff --git a/src/common/navigation.ts b/src/common/navigation.ts index fde66d2..4323817 100644 --- a/src/common/navigation.ts +++ b/src/common/navigation.ts @@ -59,6 +59,9 @@ export function setupNavigation(options: NavigationOptions): void { document.getElementById('nav-reactions'); const relaysButton: HTMLElement | null = document.getElementById('nav-relays'); + const profileLink: HTMLAnchorElement | null = document.getElementById( + 'nav-profile', + ) as HTMLAnchorElement | null; const settingsButton: HTMLElement | null = document.getElementById('nav-settings'); const aboutButton: HTMLElement | null = document.getElementById('nav-about'); @@ -186,6 +189,21 @@ export function setupNavigation(options: NavigationOptions): void { ); } + if (profileLink) { + profileLink.addEventListener('click', (event: MouseEvent): void => { + const href: string | null = profileLink.getAttribute('href'); + if (!href || !href.startsWith('/')) { + closeMobileMenu(); + return; + } + + event.preventDefault(); + wrapNavigationHandler((): void => { + options.navigateTo(href); + })(); + }); + } + if (relaysButton) { relaysButton.addEventListener( 'click', diff --git a/src/features/about/about-page.ts b/src/features/about/about-page.ts index ff4d16a..ee2aee0 100644 --- a/src/features/about/about-page.ts +++ b/src/features/about/about-page.ts @@ -40,7 +40,7 @@ export function loadAboutPage(options: AboutPageOptions): void { const postsHeader: HTMLElement | null = document.getElementById('posts-header'); if (postsHeader) { - postsHeader.textContent = 'About noxtr'; + postsHeader.textContent = 'About nox'; postsHeader.style.display = ''; } @@ -56,16 +56,16 @@ export function loadAboutPage(options: AboutPageOptions): void { options.output.innerHTML = `
-

A Practical Nostr Client

+

A Practical Relay Client

- noxtr is built as a fast single-page web client focused on reliability and day-to-day use. + nox is built as a fast single-page web client focused on reliability and day-to-day use. It keeps the protocol visible, avoids heavy abstractions, and gives you direct control over relays, identity, and timelines.

-

What Makes noxtr Different

+

What Makes nox Different

  • Relay-first controls: full relay list management, health checks, and one-click post broadcast to newly added relays.
  • Protocol-forward rendering: native support for NIP-30 custom emoji in posts, reactions, and profile metadata.
  • @@ -93,16 +93,16 @@ export function loadAboutPage(options: AboutPageOptions): void {

    Design Goal

    - noxtr prioritizes transparency over magic: when something happens on the network, you can + nox prioritizes transparency over magic: when something happens on the network, you can usually trace it in the UI. The goal is a client that stays simple enough to trust while - still being capable enough for serious Nostr usage. + still being capable enough for serious daily use.

    Donate / Zap

    - If you find noxtr useful, you can support development via Lightning Address: + If you find nox useful, you can support development via Lightning Address:

    diff --git a/src/features/home/welcome.ts b/src/features/home/welcome.ts index 2bbb463..3101004 100644 --- a/src/features/home/welcome.ts +++ b/src/features/home/welcome.ts @@ -10,6 +10,12 @@ interface ShowInputFormOptions { handleRoute: () => void; } +interface WindowWithNostr extends Window { + nostr?: { + getPublicKey: () => Promise; + }; +} + export async function showInputForm( options: ShowInputFormOptions, ): Promise { @@ -29,30 +35,66 @@ export async function showInputForm( } options.output.innerHTML = ` -
    -

    Welcome to noxtr

    -

    Connect your Nostr extension or use your private key to view your home timeline,
    or explore the global timeline.

    -
    - - +
    +
    +
    +

    Home Feed Access

    +

    Enter nox mode

    +

    + Sign in with a compatible extension for the cleanest flow, use a local private key if + you need direct control, or skip straight to the global timeline and watch the network + in motion. +

    +
    + +
    +
    + Direct relay view + Posts come from your configured relay set, not from an app server in the middle. +
    +
    + Cache-first rendering + IndexedDB keeps feeds, profiles, and timelines close for faster revisits. +
    +
    + Protocol-visible UI + Relay management, reply context, NIP-65, and profile identity stay accessible. +
    +
    -
    - -
    - - +
    -

    Private keys are stored on this device so you stay logged in after closing the app. Log out to remove it. For better security, use a Nostr extension instead.

    + +
    + +
    + + +
    +

    Private keys are stored locally so you remain signed in after closing the app. Use an extension when possible for better isolation.

    +
    -
    +
    `; const welcomeLoginBtn: HTMLElement | null = @@ -68,14 +110,15 @@ export async function showInputForm( if (welcomeLoginBtn) { welcomeLoginBtn.addEventListener('click', async (): Promise => { try { - if (!(window as any).nostr) { + const nostrWindow: WindowWithNostr = window as WindowWithNostr; + if (!nostrWindow.nostr) { alert( - 'No Nostr extension found!\n\nPlease install a Nostr browser extension like:\n- Alby (getalby.com)\n- nos2x\n- Flamingo\n\nThen reload this page.', + 'No compatible extension found!\n\nPlease install a browser extension that exposes the nostr signing API, such as:\n- Alby (getalby.com)\n- nos2x\n- Flamingo\n\nThen reload this page.', ); return; } - const pubkeyHex: string = await (window as any).nostr.getPublicKey(); + const pubkeyHex: string = await nostrWindow.nostr.getPublicKey(); if (!pubkeyHex) { alert('Failed to get public key from extension.'); return; diff --git a/src/features/relays/relays-page.ts b/src/features/relays/relays-page.ts index accd549..7759235 100644 --- a/src/features/relays/relays-page.ts +++ b/src/features/relays/relays-page.ts @@ -64,7 +64,7 @@ export function loadRelaysPage(options: RelaysPageOptions): void {
    NIP-65 (kind 10002) Relay List
    - You can publish your relay list to Nostr (so other clients can discover it), or import it back into this app. + You can publish your relay list to the network so other clients can discover it, or import it back into this app.
    -
    +
    -
    +
    - +
    +
    + +
    +
    @@ -92,25 +115,31 @@