mirror of
https://github.com/aljazceru/rabbit.git
synced 2025-12-17 22:14:26 +01:00
update
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { Show, type JSX, type Component } from 'solid-js';
|
||||
import ArrowLeft from 'heroicons/24/outline/arrow-left.svg';
|
||||
|
||||
import { useHandleCommand } from '@/hooks/useCommandBus';
|
||||
import { ColumnContext, useColumnState } from '@/components/ColumnContext';
|
||||
import ColumnContentDisplay from '@/components/ColumnContentDisplay';
|
||||
@@ -57,8 +59,14 @@ const Column: Component<ColumnProps> = (props) => {
|
||||
{(columnContent) => (
|
||||
<div class="absolute h-full w-full bg-white">
|
||||
<div class="flex h-8 shrink-0 items-center border-b bg-white px-2">
|
||||
<button class="w-full text-left" onClick={() => columnState?.clearColumnContext()}>
|
||||
<ホームに戻る
|
||||
<button
|
||||
class="flex w-full items-center gap-1"
|
||||
onClick={() => columnState?.clearColumnContext()}
|
||||
>
|
||||
<div class="inline-block h-4 w-4">
|
||||
<ArrowLeft />
|
||||
</div>
|
||||
<div>ホームに戻る</div>
|
||||
</button>
|
||||
</div>
|
||||
<ul class="flex h-full flex-col overflow-y-scroll scroll-smooth">
|
||||
|
||||
@@ -7,8 +7,17 @@ type EventLinkProps = {
|
||||
eventId: string;
|
||||
};
|
||||
|
||||
const EventLink: Component<EventLinkProps> = (props) => (
|
||||
<span class="text-blue-500 underline">{noteEncode(props.eventId)}</span>
|
||||
);
|
||||
const tryEncode = (eventId: string) => {
|
||||
try {
|
||||
return noteEncode(eventId);
|
||||
} catch (err) {
|
||||
console.error('failed to encode event id into Bech32 entity (NIP-19) but ignore', eventId, err);
|
||||
return eventId;
|
||||
}
|
||||
};
|
||||
|
||||
const EventLink: Component<EventLinkProps> = (props) => {
|
||||
return <button class="text-blue-500 underline">{tryEncode(props.eventId)}</button>;
|
||||
};
|
||||
|
||||
export default EventLink;
|
||||
|
||||
@@ -3,18 +3,18 @@ import GeneralUserMentionDisplay from '@/components/textNote/GeneralUserMentionD
|
||||
import useModalState from '@/hooks/useModalState';
|
||||
|
||||
export type MentionedUserDisplayProps = {
|
||||
mentionedUser: MentionedUser;
|
||||
pubkey: string;
|
||||
};
|
||||
|
||||
const MentionedUserDisplay = (props: MentionedUserDisplayProps) => {
|
||||
const { showProfile } = useModalState();
|
||||
|
||||
const handleClick = () => {
|
||||
showProfile(props.mentionedUser.pubkey);
|
||||
showProfile(props.pubkey);
|
||||
};
|
||||
return (
|
||||
<button class="inline text-blue-500 underline" onClick={handleClick}>
|
||||
<GeneralUserMentionDisplay pubkey={props.mentionedUser.pubkey} />
|
||||
<GeneralUserMentionDisplay pubkey={props.pubkey} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ const TextNoteContentDisplay = (props: TextNoteContentDisplayProps) => {
|
||||
return <PlainTextDisplay plainText={item} />;
|
||||
}
|
||||
if (item.type === 'MentionedUser') {
|
||||
return <MentionedUserDisplay mentionedUser={item} />;
|
||||
return <MentionedUserDisplay pubkey={item.pubkey} />;
|
||||
}
|
||||
if (item.type === 'MentionedEvent') {
|
||||
if (props.embedding) {
|
||||
@@ -43,6 +43,12 @@ const TextNoteContentDisplay = (props: TextNoteContentDisplayProps) => {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (item.data.type === 'npub' && props.embedding) {
|
||||
return <MentionedUserDisplay pubkey={item.data.data} />;
|
||||
}
|
||||
if (item.data.type === 'nprofile' && props.embedding) {
|
||||
return <MentionedUserDisplay pubkey={item.data.data.pubkey} />;
|
||||
}
|
||||
return <span class="text-blue-500 underline">{item.content}</span>;
|
||||
}
|
||||
if (item.type === 'HashTag') {
|
||||
@@ -61,6 +67,7 @@ const TextNoteContentDisplay = (props: TextNoteContentDisplayProps) => {
|
||||
}
|
||||
return <SafeLink class="text-blue-500 underline" href={item.content} />;
|
||||
}
|
||||
console.error('Not all ParsedTextNoteNodes are covered', item);
|
||||
return null;
|
||||
}}
|
||||
</For>
|
||||
|
||||
@@ -165,16 +165,7 @@ const TextNoteDisplay: Component<TextNoteDisplayProps> = (props) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
class="nostr-textnote flex flex-col"
|
||||
onClick={() => {
|
||||
// FIXME
|
||||
// columnContext?.setColumnContent({
|
||||
// type: 'Replies',
|
||||
// eventId: event().rootEvent()?.id ?? props.event.id,
|
||||
// });
|
||||
}}
|
||||
>
|
||||
<div class="nostr-textnote flex flex-col">
|
||||
<div class="flex w-full gap-1">
|
||||
<button
|
||||
class="author-icon h-10 w-10 shrink-0 overflow-hidden"
|
||||
@@ -213,7 +204,20 @@ const TextNoteDisplay: Component<TextNoteDisplayProps> = (props) => {
|
||||
{/* TODO <Match when={author()?.nip05 != null}>@{author()?.nip05}</Match> */}
|
||||
</div>
|
||||
</button>
|
||||
<div class="created-at shrink-0">{createdAt()}</div>
|
||||
<div class="created-at shrink-0">
|
||||
<button
|
||||
type="button"
|
||||
class="hover:underline"
|
||||
onClick={() => {
|
||||
columnContext?.setColumnContent({
|
||||
type: 'Replies',
|
||||
eventId: event().rootEvent()?.id ?? props.event.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{createdAt()}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref={contentRef}
|
||||
|
||||
@@ -60,8 +60,11 @@ const parseTextNote = (event: NostrEvent): ParsedTextNote => {
|
||||
const matches = [
|
||||
...event.content.matchAll(/(?:#\[(?<idx>\d+)\])/g),
|
||||
...event.content.matchAll(/#(?<hashtag>[^[-^`:-@!-/{-~\d\s][^[-^`:-@!-/{-~\s]+)/g),
|
||||
// raw NIP-19 codes, NIP-21 links (NIP-27)
|
||||
// nrelay and naddr is not supported by nostr-tools
|
||||
...event.content.matchAll(/(?<nip19>(npub|note|nprofile|nevent)1[ac-hj-np-z02-9]+)/gi),
|
||||
...event.content.matchAll(
|
||||
/(?:nostr:)?(?<mention>(npub|note|nprofile|nevent)1[ac-hj-np-z02-9]+)/gi,
|
||||
),
|
||||
...event.content.matchAll(
|
||||
/(?<url>(?:https?|wss?):\/\/[-a-zA-Z0-9.]+(?:\/[-[\]~!$&'()*+.,:;@%\w]+|\/)*(?:\?[-[\]~!$&'()*+.,/:;%@\w&=]+)?(?:#[-[\]~!$&'()*+.,/:;%@\w?&=#]+)?)/g,
|
||||
),
|
||||
@@ -117,10 +120,10 @@ const parseTextNote = (event: NostrEvent): ParsedTextNote => {
|
||||
};
|
||||
result.push(mentionedEvent);
|
||||
}
|
||||
} else if (match.groups?.nip19) {
|
||||
} else if (match.groups?.mention) {
|
||||
pushPlainText(index);
|
||||
try {
|
||||
const decoded = decode(match[0]);
|
||||
const decoded = decode(match[1]);
|
||||
const bech32Entity: Bech32Entity = {
|
||||
type: 'Bech32Entity',
|
||||
content: match[0],
|
||||
@@ -129,6 +132,8 @@ const parseTextNote = (event: NostrEvent): ParsedTextNote => {
|
||||
result.push(bech32Entity);
|
||||
} catch (e) {
|
||||
console.error(`failed to parse Bech32 entity (NIP-19) but ignore this: ${match[0]}`);
|
||||
pushPlainText(index + match[0].length);
|
||||
return;
|
||||
}
|
||||
} else if (match.groups?.hashtag) {
|
||||
pushPlainText(index);
|
||||
|
||||
@@ -286,6 +286,7 @@ export const useProfile = (propsProvider: () => UseProfileProps | null): UseProf
|
||||
// cacheTime is long so that the user see profiles instantly.
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 24 * 60 * 60 * 1000, // 1 day
|
||||
refetchInterval: 5 * 60 * 1000, // 5 min
|
||||
},
|
||||
);
|
||||
|
||||
@@ -331,7 +332,7 @@ export const useTextNote = (propsProvider: () => UseTextNoteProps | null): UseTe
|
||||
},
|
||||
);
|
||||
|
||||
const event = () => query.data;
|
||||
const event = () => query.data ?? null;
|
||||
|
||||
return { event, query };
|
||||
};
|
||||
@@ -362,6 +363,7 @@ export const useReactions = (propsProvider: () => UseReactionsProps | null): Use
|
||||
{
|
||||
staleTime: 1 * 60 * 1000, // 1 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchInterval: 1 * 60 * 1000, // 1 min
|
||||
},
|
||||
);
|
||||
|
||||
@@ -412,6 +414,7 @@ export const useDeprecatedReposts = (
|
||||
{
|
||||
staleTime: 1 * 60 * 1000, // 1 min
|
||||
cacheTime: 4 * 60 * 60 * 1000, // 4 hour
|
||||
refetchInterval: 1 * 60 * 1000, // 1 min
|
||||
},
|
||||
);
|
||||
|
||||
@@ -458,7 +461,6 @@ export const useFollowings = (propsProvider: () => UseFollowingsProps | null): U
|
||||
staleTime: 5 * 60 * 1000, // 5 min
|
||||
cacheTime: 24 * 60 * 60 * 1000, // 24 hour
|
||||
refetchOnWindowFocus: false,
|
||||
refetchInterval: 5 * 60 * 1000, // 5 min
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user