mirror of
https://github.com/aljazceru/rabbit.git
synced 2025-12-19 06:54:23 +01:00
update
This commit is contained in:
85
src/clients/useBatch.ts
Normal file
85
src/clients/useBatch.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { createSignal, createEffect, onCleanup } from 'solid-js';
|
||||||
|
|
||||||
|
export type Task<TaskArgs, TaskResult> = {
|
||||||
|
id: number;
|
||||||
|
args: TaskArgs;
|
||||||
|
resolve: (result: TaskResult) => void;
|
||||||
|
reject: (error: any) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UseBatchProps<TaskArgs, TaskResult> = {
|
||||||
|
executor: (task: Task<TaskArgs, TaskResult>[]) => void;
|
||||||
|
interval?: number;
|
||||||
|
// batchSize: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PromiseWithCallbacks<T> = {
|
||||||
|
promise: Promise<T>;
|
||||||
|
resolve: (e: T) => void;
|
||||||
|
reject: (e: any) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const promiseWithCallbacks = <T>(): PromiseWithCallbacks<T> => {
|
||||||
|
let resolve: ((e: T) => void) | undefined;
|
||||||
|
let reject: ((e: any) => void) | undefined;
|
||||||
|
|
||||||
|
const promise = new Promise<T>((resolveFn, rejectFn) => {
|
||||||
|
resolve = resolveFn;
|
||||||
|
reject = rejectFn;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resolve == null || reject == null) {
|
||||||
|
throw new Error('PromiseWithCallbacks failed to extract callbacks');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { promise, resolve, reject };
|
||||||
|
};
|
||||||
|
|
||||||
|
const useBatch = <TaskArgs, TaskResult>(
|
||||||
|
propsProvider: () => UseBatchProps<TaskArgs, TaskResult>,
|
||||||
|
) => {
|
||||||
|
const [seqId, setSeqId] = createSignal<number>(0);
|
||||||
|
const [taskQueue, setTaskQueue] = createSignal<Task<TaskArgs, TaskResult>[]>([]);
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const { executor, interval = 1000 } = propsProvider();
|
||||||
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
|
if (timeoutId == null && taskQueue().length > 0) {
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
const currentTaskQueue = taskQueue();
|
||||||
|
if (currentTaskQueue.length > 0) {
|
||||||
|
setTaskQueue([]);
|
||||||
|
executor(currentTaskQueue);
|
||||||
|
}
|
||||||
|
timeoutId = undefined;
|
||||||
|
}, interval);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const nextId = (): number => {
|
||||||
|
const id = seqId();
|
||||||
|
setSeqId((currentId) => currentId + 1);
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
// enqueue task and wait response
|
||||||
|
const exec = async (args: TaskArgs, signal?: AbortSignal): Promise<TaskResult> => {
|
||||||
|
const { promise, resolve, reject } = promiseWithCallbacks<TaskResult>();
|
||||||
|
const id = nextId();
|
||||||
|
const newTask: Task<TaskArgs, TaskResult> = { id, args, resolve, reject };
|
||||||
|
|
||||||
|
signal?.addEventListener('abort', () => {
|
||||||
|
reject(new Error('AbortError'));
|
||||||
|
setTaskQueue((currentTaskQueue) => currentTaskQueue.filter((task) => task.id !== newTask.id));
|
||||||
|
});
|
||||||
|
|
||||||
|
setTaskQueue((currentTaskQueue) => [...currentTaskQueue, newTask]);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
return { exec };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useBatch;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createQuery } from '@tanstack/solid-query';
|
import { createQuery } from '@tanstack/solid-query';
|
||||||
import { UseSubscriptionProps } from '@/clients/useSubscription';
|
import { type UseSubscriptionProps } from '@/clients/useSubscription';
|
||||||
import type { Event as NostrEvent } from 'nostr-tools/event';
|
import type { Event as NostrEvent } from 'nostr-tools/event';
|
||||||
import type { Filter } from 'nostr-tools/filter';
|
import type { Filter } from 'nostr-tools/filter';
|
||||||
import type { SimplePool } from 'nostr-tools/pool';
|
import type { SimplePool } from 'nostr-tools/pool';
|
||||||
@@ -10,6 +10,8 @@ type GetEventsArgs = {
|
|||||||
pool: SimplePool;
|
pool: SimplePool;
|
||||||
relayUrls: string[];
|
relayUrls: string[];
|
||||||
filters: Filter[];
|
filters: Filter[];
|
||||||
|
// TODO 継続的に取得する場合、Promiseでは無理なので、無理やりキャッシュにストアする仕組みを使う
|
||||||
|
continuous?: boolean;
|
||||||
options?: SubscriptionOptions;
|
options?: SubscriptionOptions;
|
||||||
signal?: AbortSignal;
|
signal?: AbortSignal;
|
||||||
};
|
};
|
||||||
@@ -52,12 +54,12 @@ const useCachedEvents = (propsProvider: () => UseSubscriptionProps) => {
|
|||||||
|
|
||||||
return createQuery(
|
return createQuery(
|
||||||
() => {
|
() => {
|
||||||
const { relayUrls, filters, options } = propsProvider();
|
const { relayUrls, filters, continuous, options } = propsProvider();
|
||||||
return ['useCachedEvents', relayUrls, filters, options] as const;
|
return ['useCachedEvents', relayUrls, filters, continuous, options] as const;
|
||||||
},
|
},
|
||||||
({ queryKey, signal }) => {
|
({ queryKey, signal }) => {
|
||||||
const [, relayUrls, filters, options] = queryKey;
|
const [, relayUrls, filters, continuous, options] = queryKey;
|
||||||
return getEvents({ pool: pool(), relayUrls, filters, options, signal });
|
return getEvents({ pool: pool(), relayUrls, filters, options, continuous, signal });
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 5 minutes
|
// 5 minutes
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { type Accessor } from 'solid-js';
|
import { createMemo, type Accessor } from 'solid-js';
|
||||||
import { type Event as NostrEvent } from 'nostr-tools/event';
|
import { type Event as NostrEvent } from 'nostr-tools/event';
|
||||||
import { type CreateQueryResult } from '@tanstack/solid-query';
|
import { createQuery, type CreateQueryResult } from '@tanstack/solid-query';
|
||||||
|
|
||||||
import useCachedEvents from '@/clients/useCachedEvents';
|
import useConfig from '@/clients/useConfig';
|
||||||
|
import useBatch, { type Task } from '@/clients/useBatch';
|
||||||
|
import useSubscription from '@/clients/useSubscription';
|
||||||
|
|
||||||
export type UseEventProps = {
|
export type UseEventProps = {
|
||||||
relayUrls: string[];
|
relayUrls: string[];
|
||||||
@@ -11,25 +13,57 @@ export type UseEventProps = {
|
|||||||
|
|
||||||
export type UseEvent = {
|
export type UseEvent = {
|
||||||
event: Accessor<NostrEvent | undefined>;
|
event: Accessor<NostrEvent | undefined>;
|
||||||
query: CreateQueryResult<NostrEvent[]>;
|
query: CreateQueryResult<NostrEvent>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useEvent = (propsProvider: () => UseEventProps): UseEvent => {
|
const { exec } = useBatch<UseEventProps, NostrEvent>(() => {
|
||||||
const query = useCachedEvents(() => {
|
return {
|
||||||
const { relayUrls, eventId } = propsProvider();
|
executor: (tasks) => {
|
||||||
return {
|
// TODO relayUrlsを考慮する
|
||||||
relayUrls,
|
const [config] = useConfig();
|
||||||
filters: [
|
const eventIdTaskMap = new Map<string, Task<UseEventProps, NostrEvent>>(
|
||||||
{
|
tasks.map((task) => [task.args.eventId, task]),
|
||||||
ids: [eventId],
|
);
|
||||||
kinds: [1],
|
const eventIds = Array.from(eventIdTaskMap.keys());
|
||||||
limit: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const event = () => query.data?.[0];
|
useSubscription(() => ({
|
||||||
|
relayUrls: config().relayUrls,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
ids: eventIds,
|
||||||
|
kinds: [1],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
continuous: false,
|
||||||
|
onEvent: (event: NostrEvent) => {
|
||||||
|
if (event.id == null) return;
|
||||||
|
const task = eventIdTaskMap.get(event.id);
|
||||||
|
// possibly, the new event received
|
||||||
|
if (task == null) return;
|
||||||
|
task.resolve(event);
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const useEvent = (propsProvider: () => UseEventProps): UseEvent => {
|
||||||
|
const props = createMemo(propsProvider);
|
||||||
|
|
||||||
|
const query = createQuery(
|
||||||
|
() => ['useEvent', props()] as const,
|
||||||
|
({ queryKey, signal }) => {
|
||||||
|
const [, currentProps] = queryKey;
|
||||||
|
return exec(currentProps, signal);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 5 minutes
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
cacheTime: 15 * 60 * 1000,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const event = () => query.data;
|
||||||
|
|
||||||
return { event, query };
|
return { event, query };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { type Accessor } from 'solid-js';
|
import { createMemo, type Accessor } from 'solid-js';
|
||||||
import { type Event as NostrEvent } from 'nostr-tools/event';
|
import { type Event as NostrEvent } from 'nostr-tools/event';
|
||||||
import { type CreateQueryResult } from '@tanstack/solid-query';
|
import { createQuery, type CreateQueryResult } from '@tanstack/solid-query';
|
||||||
|
|
||||||
import useCachedEvents from '@/clients/useCachedEvents';
|
import useConfig from '@/clients/useConfig';
|
||||||
|
import useBatch, { type Task } from '@/clients/useBatch';
|
||||||
type UseProfileProps = {
|
import useSubscription from '@/clients/useSubscription';
|
||||||
relayUrls: string[];
|
|
||||||
pubkey: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO zodにする
|
// TODO zodにする
|
||||||
// deleted等の特殊なもの
|
// deleted等の特殊なもの
|
||||||
@@ -27,28 +24,65 @@ type NonStandardProfile = {
|
|||||||
|
|
||||||
type Profile = StandardProfile & NonStandardProfile;
|
type Profile = StandardProfile & NonStandardProfile;
|
||||||
|
|
||||||
type UseProfile = {
|
type UseProfileProps = {
|
||||||
profile: Accessor<Profile | undefined>;
|
relayUrls: string[];
|
||||||
query: CreateQueryResult<NostrEvent[]>;
|
pubkey: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useProfile = (propsProvider: () => UseProfileProps): UseProfile => {
|
type UseProfile = {
|
||||||
const query = useCachedEvents(() => {
|
profile: Accessor<Profile | undefined>;
|
||||||
const { relayUrls, pubkey } = propsProvider();
|
query: CreateQueryResult<NostrEvent>;
|
||||||
return {
|
};
|
||||||
relayUrls,
|
|
||||||
filters: [
|
const { exec } = useBatch<UseProfileProps, NostrEvent>(() => {
|
||||||
{
|
return {
|
||||||
kinds: [0],
|
executor: (tasks) => {
|
||||||
authors: [pubkey],
|
// TODO relayUrlsを考慮する
|
||||||
limit: 1,
|
const [config] = useConfig();
|
||||||
|
const pubkeyTaskMap = new Map<string, Task<UseProfileProps, NostrEvent>>(
|
||||||
|
tasks.map((task) => [task.args.pubkey, task]),
|
||||||
|
);
|
||||||
|
const pubkeys = Array.from(pubkeyTaskMap.keys());
|
||||||
|
|
||||||
|
useSubscription(() => ({
|
||||||
|
relayUrls: config().relayUrls,
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
kinds: [0],
|
||||||
|
authors: pubkeys,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
continuous: false,
|
||||||
|
onEvent: (event: NostrEvent) => {
|
||||||
|
if (event.id == null) return;
|
||||||
|
const task = pubkeyTaskMap.get(event.pubkey);
|
||||||
|
// possibly, the new event received
|
||||||
|
if (task == null) return;
|
||||||
|
task.resolve(event);
|
||||||
},
|
},
|
||||||
],
|
}));
|
||||||
};
|
},
|
||||||
});
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const useProfile = (propsProvider: () => UseProfileProps): UseProfile => {
|
||||||
|
const props = createMemo(propsProvider);
|
||||||
|
|
||||||
|
const query = createQuery(
|
||||||
|
() => ['useProfile', props()] as const,
|
||||||
|
({ queryKey, signal }) => {
|
||||||
|
const [, currentProps] = queryKey;
|
||||||
|
return exec(currentProps, signal);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// 5 minutes
|
||||||
|
staleTime: 5 * 60 * 1000,
|
||||||
|
cacheTime: 15 * 60 * 1000,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const profile = () => {
|
const profile = () => {
|
||||||
const maybeProfile = query.data?.[0];
|
const maybeProfile = query.data;
|
||||||
if (maybeProfile == null) return undefined;
|
if (maybeProfile == null) return undefined;
|
||||||
|
|
||||||
// TODO 大きすぎたりしないかどうか、JSONかどうかのチェック
|
// TODO 大きすぎたりしないかどうか、JSONかどうかのチェック
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ export type UseSubscriptionProps = {
|
|||||||
relayUrls: string[];
|
relayUrls: string[];
|
||||||
filters: Filter[];
|
filters: Filter[];
|
||||||
options?: SubscriptionOptions;
|
options?: SubscriptionOptions;
|
||||||
|
// subscribe not only stored events but also new events published after the subscription
|
||||||
|
// default is true
|
||||||
|
continuous?: boolean;
|
||||||
|
onEvent?: (event: NostrEvent) => void;
|
||||||
|
signal?: AbortSignal;
|
||||||
};
|
};
|
||||||
|
|
||||||
const sortEvents = (events: NostrEvent[]) =>
|
const sortEvents = (events: NostrEvent[]) =>
|
||||||
@@ -21,7 +26,7 @@ const useSubscription = (propsProvider: () => UseSubscriptionProps | undefined)
|
|||||||
const props = propsProvider();
|
const props = propsProvider();
|
||||||
if (props == null) return;
|
if (props == null) return;
|
||||||
|
|
||||||
const { relayUrls, filters, options } = props;
|
const { relayUrls, filters, options, onEvent, continuous = true } = props;
|
||||||
|
|
||||||
const sub = pool().sub(relayUrls, filters, options);
|
const sub = pool().sub(relayUrls, filters, options);
|
||||||
let pushed = false;
|
let pushed = false;
|
||||||
@@ -29,6 +34,9 @@ const useSubscription = (propsProvider: () => UseSubscriptionProps | undefined)
|
|||||||
const storedEvents: NostrEvent[] = [];
|
const storedEvents: NostrEvent[] = [];
|
||||||
|
|
||||||
sub.on('event', (event: NostrEvent) => {
|
sub.on('event', (event: NostrEvent) => {
|
||||||
|
if (onEvent != null) {
|
||||||
|
onEvent(event);
|
||||||
|
}
|
||||||
if (!eose) {
|
if (!eose) {
|
||||||
pushed = true;
|
pushed = true;
|
||||||
storedEvents.push(event);
|
storedEvents.push(event);
|
||||||
@@ -41,6 +49,10 @@ const useSubscription = (propsProvider: () => UseSubscriptionProps | undefined)
|
|||||||
sub.on('eose', () => {
|
sub.on('eose', () => {
|
||||||
eose = true;
|
eose = true;
|
||||||
setEvents(sortEvents(storedEvents));
|
setEvents(sortEvents(storedEvents));
|
||||||
|
|
||||||
|
if (!continuous) {
|
||||||
|
sub.unsub();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// avoid updating an array too rapidly while this is fetching stored events
|
// avoid updating an array too rapidly while this is fetching stored events
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ const DeprecatedRepost: Component<DeprecatedRepostProps> = (props) => {
|
|||||||
{' Reposted'}
|
{' Reposted'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Show when={event() != null} fallback={<Show when={eventQuery.isLoading}>loading</Show>}>
|
<Show
|
||||||
|
when={event() != null}
|
||||||
|
fallback={<Show when={eventQuery.isLoading}>loading {eventId()}</Show>}
|
||||||
|
>
|
||||||
<TextNote event={event()} />
|
<TextNote event={event()} />
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import useProfile from '@/clients/useProfile';
|
|||||||
import useConfig from '@/clients/useConfig';
|
import useConfig from '@/clients/useConfig';
|
||||||
import usePubkey from '@/clients/usePubkey';
|
import usePubkey from '@/clients/usePubkey';
|
||||||
import useCommands from '@/clients/useCommands';
|
import useCommands from '@/clients/useCommands';
|
||||||
import useReactions from '@/clients/useReactions';
|
// import useReactions from '@/clients/useReactions';
|
||||||
import useDatePulser from '@/hooks/useDatePulser';
|
import useDatePulser from '@/hooks/useDatePulser';
|
||||||
import { formatRelative } from '@/utils/formatDate';
|
import { formatRelative } from '@/utils/formatDate';
|
||||||
import ColumnItem from '@/components/ColumnItem';
|
import ColumnItem from '@/components/ColumnItem';
|
||||||
@@ -33,6 +33,7 @@ const TextNote: Component<TextNoteProps> = (props) => {
|
|||||||
pubkey: props.event.pubkey,
|
pubkey: props.event.pubkey,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
/*
|
||||||
const {
|
const {
|
||||||
reactions,
|
reactions,
|
||||||
isReactedBy,
|
isReactedBy,
|
||||||
@@ -43,6 +44,8 @@ const TextNote: Component<TextNoteProps> = (props) => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const isReactedByMe = createMemo(() => isReactedBy(pubkey()));
|
const isReactedByMe = createMemo(() => isReactedBy(pubkey()));
|
||||||
|
*/
|
||||||
|
const isReactedByMe = () => false;
|
||||||
|
|
||||||
const replyingToPubKeys = createMemo(() =>
|
const replyingToPubKeys = createMemo(() =>
|
||||||
props.event.tags.filter((tag) => tag[0] === 'p').map((e) => e[1]),
|
props.event.tags.filter((tag) => tag[0] === 'p').map((e) => e[1]),
|
||||||
@@ -61,10 +64,12 @@ const TextNote: Component<TextNoteProps> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleReaction: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (ev) => {
|
const handleReaction: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (ev) => {
|
||||||
|
/*
|
||||||
if (isReactedByMe()) {
|
if (isReactedByMe()) {
|
||||||
// TODO remove reaction
|
// TODO remove reaction
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
commands
|
commands
|
||||||
.publishReaction({
|
.publishReaction({
|
||||||
@@ -75,7 +80,7 @@ const TextNote: Component<TextNoteProps> = (props) => {
|
|||||||
notifyPubkey: props.event.pubkey,
|
notifyPubkey: props.event.pubkey,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
reactionsQuery.refetch();
|
// reactionsQuery.refetch();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -141,7 +146,7 @@ const TextNote: Component<TextNoteProps> = (props) => {
|
|||||||
<HeartSolid />
|
<HeartSolid />
|
||||||
</Show>
|
</Show>
|
||||||
</button>
|
</button>
|
||||||
<div class="text-sm text-zinc-400">{reactions().length}</div>
|
{/* <div class="text-sm text-zinc-400">{reactions().length}</div> */}
|
||||||
</div>
|
</div>
|
||||||
<button class="h-4 w-4 text-zinc-400">
|
<button class="h-4 w-4 text-zinc-400">
|
||||||
<EllipsisHorizontal />
|
<EllipsisHorizontal />
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ const Reaction: Component<ReactionProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="notification-event">
|
<div class="notification-event">
|
||||||
<Show when={reactedEvent() != null} fallback="loading">
|
<Show when={reactedEvent() != null} fallback={<>loading {eventId()}</>}>
|
||||||
<TextNote event={reactedEvent()} />
|
<TextNote event={reactedEvent()} />
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const [currentDate, setCurrentDate] = createSignal(new Date());
|
|||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
setCurrentDate(new Date());
|
setCurrentDate(new Date());
|
||||||
}, 10000);
|
}, 7000);
|
||||||
|
|
||||||
const useDatePulser = (): Accessor<Date> => {
|
const useDatePulser = (): Accessor<Date> => {
|
||||||
return currentDate;
|
return currentDate;
|
||||||
|
|||||||
@@ -32,6 +32,21 @@ useShortcutKeys({
|
|||||||
onShortcut: (s) => console.log(s),
|
onShortcut: (s) => console.log(s),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const dummyTextNote = (
|
||||||
|
<TextNote
|
||||||
|
event={
|
||||||
|
{
|
||||||
|
id: 12345,
|
||||||
|
kind: 1,
|
||||||
|
pubkey: pubkeyHex,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
tags: [],
|
||||||
|
content: 'hello',
|
||||||
|
} as NostrEvent
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
const Home: Component = () => {
|
const Home: Component = () => {
|
||||||
const [config] = useConfig();
|
const [config] = useConfig();
|
||||||
const commands = useCommands();
|
const commands = useCommands();
|
||||||
@@ -47,6 +62,7 @@ const Home: Component = () => {
|
|||||||
kinds: [1, 6],
|
kinds: [1, 6],
|
||||||
authors: followings()?.map((f) => f.pubkey) ?? [pubkeyHex],
|
authors: followings()?.map((f) => f.pubkey) ?? [pubkeyHex],
|
||||||
limit: 25,
|
limit: 25,
|
||||||
|
since: Math.floor(Date.now() / 1000) - 12 * 60 * 60,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
@@ -117,18 +133,6 @@ const Home: Component = () => {
|
|||||||
<SideBar postForm={() => <NotePostForm onPost={handlePost} />} />
|
<SideBar postForm={() => <NotePostForm onPost={handlePost} />} />
|
||||||
<div class="flex flex-row overflow-y-hidden overflow-x-scroll">
|
<div class="flex flex-row overflow-y-hidden overflow-x-scroll">
|
||||||
<Column name="ホーム" width="widest">
|
<Column name="ホーム" width="widest">
|
||||||
<TextNote
|
|
||||||
event={
|
|
||||||
{
|
|
||||||
id: 12345,
|
|
||||||
kind: 1,
|
|
||||||
pubkey: pubkeyHex,
|
|
||||||
created_at: Math.floor(Date.now() / 1000),
|
|
||||||
tags: [],
|
|
||||||
content: 'hello',
|
|
||||||
} as NostrEvent
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Timeline events={followingsPosts()} />
|
<Timeline events={followingsPosts()} />
|
||||||
</Column>
|
</Column>
|
||||||
<Column name="通知" width="medium">
|
<Column name="通知" width="medium">
|
||||||
|
|||||||
Reference in New Issue
Block a user