From 9893945f5537e8c5a14661299a3b3fbda18a03d7 Mon Sep 17 00:00:00 2001 From: Danny Morabito Date: Fri, 11 Apr 2025 22:26:00 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Enhance=20app=20with=20multi-CCN=20?= =?UTF-8?q?support=20and=20improved=20UX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- electron.vite.config.ts | 3 +- package.json | 1 + src/arx-icons.ts | 64 ++++ src/assets/icons/arbor.svg | 15 + src/assets/icons/calendar.svg | 15 + src/assets/icons/howl.svg | 15 + src/assets/icons/letters.svg | 15 + src/assets/icons/market.svg | 15 + src/assets/icons/oracle.svg | 18 + src/assets/icons/pool.svg | 15 + src/assets/icons/settings.svg | 15 + src/assets/icons/wallet.svg | 15 + src/components/Arbor/ForumCategory.ts | 6 +- src/components/Arbor/ForumPost.ts | 6 +- .../Arbor/{ForumTopic.ts => ForumThread.ts} | 32 +- src/components/General/Dialog.ts | 11 +- src/components/General/Select.ts | 14 +- src/components/General/Textarea.ts | 5 +- src/components/Header.ts | 6 +- src/components/InitialSetup.ts | 320 ++++++++++++------ src/components/Setup/CCNList.ts | 56 +++ src/components/Sidebar.ts | 12 +- src/electron/main.ts | 11 +- src/electron/preload.ts | 1 - src/electron/relayManager.ts | 22 +- src/main.ts | 64 +++- src/relayManager.d.ts | 1 - src/routes/Arbor/Home.ts | 54 +-- src/routes/Arbor/NewPost.ts | 28 +- .../Arbor/{NewTopic.ts => NewThread.ts} | 59 ++-- .../Arbor/{TopicView.ts => ThreadView.ts} | 32 +- src/routes/Home.ts | 35 +- src/routes/router.ts | 116 ++++++- tsconfig.json | 3 +- 34 files changed, 792 insertions(+), 308 deletions(-) create mode 100644 src/arx-icons.ts create mode 100644 src/assets/icons/arbor.svg create mode 100644 src/assets/icons/calendar.svg create mode 100644 src/assets/icons/howl.svg create mode 100644 src/assets/icons/letters.svg create mode 100644 src/assets/icons/market.svg create mode 100644 src/assets/icons/oracle.svg create mode 100644 src/assets/icons/pool.svg create mode 100644 src/assets/icons/settings.svg create mode 100644 src/assets/icons/wallet.svg rename src/components/Arbor/{ForumTopic.ts => ForumThread.ts} (92%) create mode 100644 src/components/Setup/CCNList.ts rename src/routes/Arbor/{NewTopic.ts => NewThread.ts} (61%) rename src/routes/Arbor/{TopicView.ts => ThreadView.ts} (90%) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index ad64ea2..0e24a3f 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -1,5 +1,5 @@ -import { fileURLToPath, URL } from "node:url"; import { defineConfig, externalizeDepsPlugin } from "electron-vite"; +import { fileURLToPath, URL } from "node:url"; import { resolve } from "path"; export default defineConfig({ @@ -40,6 +40,7 @@ export default defineConfig({ "@components": fileURLToPath( new URL("./src/components", import.meta.url) ), + "@assets": fileURLToPath(new URL("./src/assets", import.meta.url)), "@": fileURLToPath(new URL("./src", import.meta.url)), }, }, diff --git a/package.json b/package.json index 3ae3477..efcea97 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "@nostr/tools": "npm:@jsr/nostr__tools", "@open-wc/lit-helpers": "^0.7.0", "@std/encoding": "npm:@jsr/std__encoding", + "iconify-icon": "^2.3.0", "lit": "^3.2.1", "markdown-it": "^14.1.0" } diff --git a/src/arx-icons.ts b/src/arx-icons.ts new file mode 100644 index 0000000..97545d3 --- /dev/null +++ b/src/arx-icons.ts @@ -0,0 +1,64 @@ +import arborIcon from '@assets/icons/arbor.svg?raw'; +import calendarIcon from '@assets/icons/calendar.svg?raw'; +import howlIcon from '@assets/icons/howl.svg?raw'; +import lettersIcon from '@assets/icons/letters.svg?raw'; +import marketIcon from '@assets/icons/market.svg?raw'; +import oracleIcon from '@assets/icons/oracle.svg?raw'; +import poolIcon from '@assets/icons/pool.svg?raw'; +import settingsIcon from '@assets/icons/settings.svg?raw'; +import walletIcon from '@assets/icons/wallet.svg?raw'; +import { addIcon } from 'iconify-icon'; + +addIcon('arx:letters', { + width: 52, + height: 46, + body: lettersIcon, +}); + +addIcon('arx:howl', { + width: 48, + height: 55, + body: howlIcon, +}); + +addIcon('arx:calendar', { + width: 51, + height: 51, + body: calendarIcon, +}); + +addIcon('arx:arbor', { + width: 40, + height: 52, + body: arborIcon, +}); + +addIcon('arx:market', { + width: 48, + height: 44, + body: marketIcon, +}); + +addIcon('arx:wallet', { + width: 50, + height: 49, + body: walletIcon, +}); + +addIcon('arx:pool', { + width: 49, + height: 45, + body: poolIcon, +}); + +addIcon('arx:oracle', { + width: 49, + height: 44, + body: oracleIcon, +}); + +addIcon('arx:settings', { + width: 42, + height: 44, + body: settingsIcon, +}); diff --git a/src/assets/icons/arbor.svg b/src/assets/icons/arbor.svg new file mode 100644 index 0000000..1b38127 --- /dev/null +++ b/src/assets/icons/arbor.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/assets/icons/calendar.svg b/src/assets/icons/calendar.svg new file mode 100644 index 0000000..5c014a3 --- /dev/null +++ b/src/assets/icons/calendar.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/assets/icons/howl.svg b/src/assets/icons/howl.svg new file mode 100644 index 0000000..c5d33e8 --- /dev/null +++ b/src/assets/icons/howl.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/assets/icons/letters.svg b/src/assets/icons/letters.svg new file mode 100644 index 0000000..ea927c3 --- /dev/null +++ b/src/assets/icons/letters.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/assets/icons/market.svg b/src/assets/icons/market.svg new file mode 100644 index 0000000..b39f1b7 --- /dev/null +++ b/src/assets/icons/market.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/assets/icons/oracle.svg b/src/assets/icons/oracle.svg new file mode 100644 index 0000000..f7b4e93 --- /dev/null +++ b/src/assets/icons/oracle.svg @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/src/assets/icons/pool.svg b/src/assets/icons/pool.svg new file mode 100644 index 0000000..f8f4e66 --- /dev/null +++ b/src/assets/icons/pool.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/assets/icons/settings.svg b/src/assets/icons/settings.svg new file mode 100644 index 0000000..6d8ade9 --- /dev/null +++ b/src/assets/icons/settings.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/assets/icons/wallet.svg b/src/assets/icons/wallet.svg new file mode 100644 index 0000000..00db564 --- /dev/null +++ b/src/assets/icons/wallet.svg @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/src/components/Arbor/ForumCategory.ts b/src/components/Arbor/ForumCategory.ts index 06609ba..64d915e 100644 --- a/src/components/Arbor/ForumCategory.ts +++ b/src/components/Arbor/ForumCategory.ts @@ -60,12 +60,12 @@ export class ArborForumCategory extends LitElement {
${this.title}
-
No topics yet...
+
No threads yet...
`; diff --git a/src/components/Arbor/ForumPost.ts b/src/components/Arbor/ForumPost.ts index 3558b53..1c26a4d 100644 --- a/src/components/Arbor/ForumPost.ts +++ b/src/components/Arbor/ForumPost.ts @@ -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, diff --git a/src/components/Arbor/ForumTopic.ts b/src/components/Arbor/ForumThread.ts similarity index 92% rename from src/components/Arbor/ForumTopic.ts rename to src/components/Arbor/ForumThread.ts index d101e41..7705dd2 100644 --- a/src/components/Arbor/ForumTopic.ts +++ b/src/components/Arbor/ForumThread.ts @@ -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` -
-
-
-
+
+
+
+
${this.title} diff --git a/src/components/General/Dialog.ts b/src/components/General/Dialog.ts index 59b3f4d..5c949e9 100644 --- a/src/components/General/Dialog.ts +++ b/src/components/General/Dialog.ts @@ -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`
diff --git a/src/components/General/Select.ts b/src/components/General/Select.ts index f387ecc..38ec5d4 100644 --- a/src/components/General/Select.ts +++ b/src/components/General/Select.ts @@ -11,7 +11,7 @@ export class StyledSelect extends LitElement { @property() name = ''; @property({ type: Boolean }) required = false; @property() label = ''; - @property({ type: Array }) options = []; + @property({ type: Array }) options: T[] = []; @property() valueMapper?: (option: T) => string; @property() textMapper?: (option: T) => string; @@ -106,15 +106,17 @@ export class StyledSelect 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 extends LitElement { const optionText = this._getOptionText(option); return html`