From ad8f51f51153948694271d25504b78fcf352d08e Mon Sep 17 00:00:00 2001 From: Shusui MOYATANI Date: Wed, 10 Jan 2024 20:25:08 +0900 Subject: [PATCH] feat: show profile json --- src/components/modal/EventDebugModal.tsx | 20 +++++-- src/components/modal/ProfileDisplay.tsx | 47 ++++++++++----- src/components/utils/useContextMenu.tsx | 74 +++++++++++++++++++++--- src/locales/en.ts | 2 + src/locales/ja.ts | 2 + 5 files changed, 119 insertions(+), 26 deletions(-) diff --git a/src/components/modal/EventDebugModal.tsx b/src/components/modal/EventDebugModal.tsx index 89ef0ae..f8b697c 100644 --- a/src/components/modal/EventDebugModal.tsx +++ b/src/components/modal/EventDebugModal.tsx @@ -1,4 +1,4 @@ -import { Component, createMemo } from 'solid-js'; +import { Component, createMemo, Show } from 'solid-js'; import { type Event as NostrEvent } from 'nostr-tools/pure'; @@ -8,6 +8,7 @@ import usePool from '@/nostr/usePool'; export type EventDebugModalProps = { event: NostrEvent; + extra?: string; onClose: () => void; }; @@ -22,17 +23,26 @@ const EventDebugModal: Component = (props) => { return ( -
-

JSON

+
+

Event JSON

           {json()}
         
- +
-
+ +
+

Extra

+
+            {props.extra}
+          
+
+
+

Found in these relays

+

If this is empty, it is from the cache.

           {seenOn()}
         
diff --git a/src/components/modal/ProfileDisplay.tsx b/src/components/modal/ProfileDisplay.tsx index 4e07401..1f7464d 100644 --- a/src/components/modal/ProfileDisplay.tsx +++ b/src/components/modal/ProfileDisplay.tsx @@ -9,6 +9,7 @@ import ExclamationCircle from 'heroicons/24/solid/exclamation-circle.svg'; import TextNoteContentDisplay from '@/components/event/textNote/TextNoteContentDisplay'; import BasicModal from '@/components/modal/BasicModal'; +import EventDebugModal from '@/components/modal/EventDebugModal'; import UserList from '@/components/modal/UserList'; import Timeline from '@/components/timeline/Timeline'; import SafeLink from '@/components/utils/SafeLink'; @@ -58,7 +59,7 @@ const ProfileDisplay: Component = (props) => { const [updatingContacts, setUpdatingContacts] = createSignal(false); const [hoverFollowButton, setHoverFollowButton] = createSignal(false); const [showFollowers, setShowFollowers] = createSignal(false); - const [modal, setModal] = createSignal<'Following' | null>(null); + const [modal, setModal] = createSignal<'Following' | 'EventDebugModal' | null>(null); const closeModal = () => setModal(null); const { @@ -219,22 +220,33 @@ const ProfileDisplay: Component = (props) => { }, }, { - content: i18n.t('profile.addUserColumn'), + content: i18n.t('profile.showJSON'), onSelect: () => { - const columnName = profile()?.name ?? npub(); - saveColumn(createPostsColumn({ name: columnName, pubkey: props.pubkey })); - request({ command: 'moveToLastColumn' }).catch((err) => console.error(err)); - props.onClose?.(); + setModal('EventDebugModal'); }, }, { - content: i18n.t('profile.addUserHomeColumn'), - onSelect: () => { - const columnName = `${i18n.t('column.home')} / ${profile()?.name ?? npub()}`; - saveColumn(createFollowingColumn({ name: columnName, pubkey: props.pubkey })); - request({ command: 'moveToLastColumn' }).catch((err) => console.error(err)); - props.onClose?.(); - }, + content: i18n.t('profile.addColumn'), + items: [ + { + content: i18n.t('profile.addUserColumn'), + onSelect: () => { + const columnName = profile()?.name ?? npub(); + saveColumn(createPostsColumn({ name: columnName, pubkey: props.pubkey })); + request({ command: 'moveToLastColumn' }).catch((err) => console.error(err)); + props.onClose?.(); + }, + }, + { + content: i18n.t('profile.addUserHomeColumn'), + onSelect: () => { + const columnName = `${i18n.t('column.home')} / ${profile()?.name ?? npub()}`; + saveColumn(createFollowingColumn({ name: columnName, pubkey: props.pubkey })); + request({ command: 'moveToLastColumn' }).catch((err) => console.error(err)); + props.onClose?.(); + }, + }, + ], }, { content: !isMuted() ? i18n.t('profile.mute') : i18n.t('profile.unmute'), @@ -461,6 +473,15 @@ const ProfileDisplay: Component = (props) => { e} onClose={closeModal} /> + + {(event) => ( + + )} +
    diff --git a/src/components/utils/useContextMenu.tsx b/src/components/utils/useContextMenu.tsx index 4dda01d..e349cc9 100644 --- a/src/components/utils/useContextMenu.tsx +++ b/src/components/utils/useContextMenu.tsx @@ -1,23 +1,37 @@ -import { createMemo, For, type Component, type JSX } from 'solid-js'; +import { createMemo, For, Switch, Match, type Component, type JSX } from 'solid-js'; + +import ChevronRight from 'heroicons/24/outline/chevron-right.svg'; import usePopup, { type UsePopupProps } from '@/components/utils/usePopup'; -export type MenuItem = { +export type SelectableItem = { content: JSX.Element; when?: () => boolean; - onSelect?: () => void; + onSelect: () => void; }; +export type SubMenu = Omit & { + content: JSX.Element; + items: (SelectableItem | SubMenu)[]; +}; + +export type MenuItem = SelectableItem | SubMenu; + export type UseContextMenuProps = Omit & { - menu: MenuItem[]; + menu: (MenuItem | SubMenu)[]; }; -export type MenuItemDisplayProps = { - item: MenuItem; +export type SelectableItemDisplayProps = { + item: SelectableItem; onClose: () => void; }; -const MenuItemDisplay: Component = (props) => { +export type SubMenuDisplayProps = { + submenu: SubMenu; + onClose: () => void; +}; + +const SelectableItemDisplay: Component = (props) => { const handleClick = () => { props.item?.onSelect?.(); props.onClose(); @@ -32,15 +46,59 @@ const MenuItemDisplay: Component = (props) => { ); }; +const SubMenuDisplay: Component = (props) => { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + const contextMenuPopup = useContextMenu(() => ({ + menu: props.submenu.items, + position: 'right', + })); + + const handleClick = () => { + contextMenuPopup.open(); + }; + + return ( +
  • + + {contextMenuPopup.popup()} +
  • + ); +}; + +const ensureSelectableItem = (item: MenuItem): SelectableItem | null => { + if ('onSelect' in item) return item; + return null; +}; + +const ensureSubMenu = (item: MenuItem): SubMenu | null => { + if ('items' in item) return item; + return null; +}; + const useContextMenu = (propsProvider: () => UseContextMenuProps) => { const props = createMemo(propsProvider); const popup = usePopup(() => ({ + ensureWidth: 300, ...props(), popup: (
      e.when == null || e.when())}> - {(item: MenuItem) => popup.close()} />} + {(item) => ( + + + {(v) => popup.close()} />} + + + {(v) => popup.close()} />} + + + )}
    ), diff --git a/src/locales/en.ts b/src/locales/en.ts index 9500b58..a0f22b1 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -59,10 +59,12 @@ export default { followingCurrently: 'Following', followsYou: 'follows you', copyPubkey: 'Copy ID', + showJSON: 'Show JSON', mute: 'Mute', unmute: 'Unmute', followMyself: 'Follow myself', unfollowMyself: 'Unfollow myself', + addColumn: 'Add column', addUserColumn: 'Add user column', addUserHomeColumn: 'Add home column', confirmUnfollow: 'Do you really want to unfollow?', diff --git a/src/locales/ja.ts b/src/locales/ja.ts index 1b23b62..7f00c55 100644 --- a/src/locales/ja.ts +++ b/src/locales/ja.ts @@ -58,10 +58,12 @@ export default { followingCurrently: 'フォロー中', followsYou: 'フォローされています', copyPubkey: 'IDをコピー', + showJSON: 'JSONを確認', mute: 'ミュート', unmute: 'ミュート解除', followMyself: '自分をフォロー', unfollowMyself: '自分をフォロー解除', + addColumn: 'カラムを追加', addUserColumn: 'ユーザカラムを追加', addUserHomeColumn: 'ホームカラムを追加', confirmUnfollow: '本当にフォロー解除しますか?',