mirror of
https://github.com/aljazceru/rabbit.git
synced 2025-12-17 05:54:19 +01:00
update
This commit is contained in:
32
.eslintrc.js
32
.eslintrc.js
@@ -34,6 +34,21 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
'prettier/prettier': 'error',
|
'prettier/prettier': 'error',
|
||||||
|
'no-console': ['off'],
|
||||||
|
'no-alert': ['off'],
|
||||||
|
'import/order': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||||
|
'newlines-between': 'always',
|
||||||
|
pathGroupsExcludedImportTypes: ['builtin'],
|
||||||
|
alphabetize: { order: 'asc', caseInsensitive: true },
|
||||||
|
pathGroups: [
|
||||||
|
{ pattern: 'solid-js*', group: 'external', position: 'before' },
|
||||||
|
{ pattern: '@/', group: 'internal', position: 'before' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
linkComponents: ['Link'],
|
linkComponents: ['Link'],
|
||||||
@@ -45,23 +60,6 @@ module.exports = {
|
|||||||
extensions: ['.ts', '.tsx'],
|
extensions: ['.ts', '.tsx'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'import/order': [
|
|
||||||
'warn',
|
|
||||||
{
|
|
||||||
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
|
||||||
'newlines-between': 'always',
|
|
||||||
pathGroupsExcludedImportTypes: ['builtin'],
|
|
||||||
alphabetize: { order: 'asc', caseInsensitive: true },
|
|
||||||
pathGroups: [
|
|
||||||
{ pattern: 'src/types/**', group: 'internal', position: 'before' },
|
|
||||||
{
|
|
||||||
pattern: 'src/repositories/**',
|
|
||||||
group: 'internal',
|
|
||||||
position: 'before',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tailwindcss: {
|
tailwindcss: {
|
||||||
whitelist: [
|
whitelist: [
|
||||||
'h-fill-available',
|
'h-fill-available',
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
"dev": "npm run generatePackageInfo && vite",
|
"dev": "npm run generatePackageInfo && vite",
|
||||||
"build": "npm run generatePackageInfo && vite build",
|
"build": "npm run generatePackageInfo && vite build",
|
||||||
"serve": "npm run generatePackageInfo && vite preview",
|
"serve": "npm run generatePackageInfo && vite preview",
|
||||||
"lint": "eslint .",
|
"lint": "eslint --cache .",
|
||||||
|
"fix": "eslint --cache --fix .",
|
||||||
"tsc": "tsc --noEmit --skipLibCheck",
|
"tsc": "tsc --noEmit --skipLibCheck",
|
||||||
"test": "vitest run --no-watch",
|
"test": "vitest run --no-watch",
|
||||||
"watch-test": "vitest --watch",
|
"watch-test": "vitest --watch",
|
||||||
"cover": "vitest run --coverage",
|
"cover": "vitest run --coverage",
|
||||||
"fix": "eslint --fix .",
|
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"generatePackageInfo": "node -e 'import(\"./scripts/generatePackageInfo.mjs\").then((m) => m.default())'",
|
"generatePackageInfo": "node -e 'import(\"./scripts/generatePackageInfo.mjs\").then((m) => m.default())'",
|
||||||
"checkLicense": "node -e 'import(\"./scripts/checkLicense.mjs\").then((m) => m.default())'"
|
"checkLicense": "node -e 'import(\"./scripts/checkLicense.mjs\").then((m) => m.default())'"
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { createEffect, onCleanup, lazy, type Component } from 'solid-js';
|
import { createEffect, onCleanup, lazy, type Component } from 'solid-js';
|
||||||
|
|
||||||
import { Routes, Route } from '@solidjs/router';
|
import { Routes, Route } from '@solidjs/router';
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/solid-query';
|
|
||||||
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
|
|
||||||
import { persistQueryClient } from '@tanstack/query-persist-client-core';
|
import { persistQueryClient } from '@tanstack/query-persist-client-core';
|
||||||
|
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/solid-query';
|
||||||
|
|
||||||
const Home = lazy(() => import('@/pages/Home'));
|
const Home = lazy(() => import('@/pages/Home'));
|
||||||
const Hello = lazy(() => import('@/pages/Hello'));
|
const Hello = lazy(() => import('@/pages/Hello'));
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Show, type JSX, type Component } from 'solid-js';
|
import { Show, type JSX, type Component } from 'solid-js';
|
||||||
|
|
||||||
import ArrowLeft from 'heroicons/24/outline/arrow-left.svg';
|
import ArrowLeft from 'heroicons/24/outline/arrow-left.svg';
|
||||||
|
|
||||||
import { useHandleCommand } from '@/hooks/useCommandBus';
|
|
||||||
import { TimelineContext, useTimelineState } from '@/components/TimelineContext';
|
|
||||||
import TimelineContentDisplay from '@/components/TimelineContentDisplay';
|
import TimelineContentDisplay from '@/components/TimelineContentDisplay';
|
||||||
|
import { TimelineContext, useTimelineState } from '@/components/TimelineContext';
|
||||||
|
import { useHandleCommand } from '@/hooks/useCommandBus';
|
||||||
|
|
||||||
export type ColumnProps = {
|
export type ColumnProps = {
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import useConfig, { type Config } from '@/nostr/useConfig';
|
|
||||||
import { createSignal, For, type JSX } from 'solid-js';
|
import { createSignal, For, type JSX } from 'solid-js';
|
||||||
|
|
||||||
import XMark from 'heroicons/24/outline/x-mark.svg';
|
import XMark from 'heroicons/24/outline/x-mark.svg';
|
||||||
|
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
|
import useConfig, { type Config } from '@/nostr/useConfig';
|
||||||
|
|
||||||
import UserNameDisplay from './UserDisplayName';
|
import UserNameDisplay from './UserDisplayName';
|
||||||
|
|
||||||
type ConfigProps = {
|
type ConfigProps = {
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
// NIP-18 (DEPRECATED)
|
// NIP-18 (DEPRECATED)
|
||||||
import { type Component, createMemo } from 'solid-js';
|
import { type Component, createMemo } from 'solid-js';
|
||||||
import { Event as NostrEvent } from 'nostr-tools';
|
|
||||||
import ArrowPathRoundedSquare from 'heroicons/24/outline/arrow-path-rounded-square.svg';
|
import ArrowPathRoundedSquare from 'heroicons/24/outline/arrow-path-rounded-square.svg';
|
||||||
|
import { Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import ColumnItem from '@/components/ColumnItem';
|
import ColumnItem from '@/components/ColumnItem';
|
||||||
import UserDisplayName from '@/components/UserDisplayName';
|
import UserDisplayName from '@/components/UserDisplayName';
|
||||||
import eventWrapper from '@/core/event';
|
import eventWrapper from '@/core/event';
|
||||||
import useFormatDate from '@/hooks/useFormatDate';
|
import useFormatDate from '@/hooks/useFormatDate';
|
||||||
import useModalState from '@/hooks/useModalState';
|
import useModalState from '@/hooks/useModalState';
|
||||||
|
|
||||||
import TextNoteDisplayById from './textNote/TextNoteDisplayById';
|
import TextNoteDisplayById from './textNote/TextNoteDisplayById';
|
||||||
|
|
||||||
export type DeprecatedRepostProps = {
|
export type DeprecatedRepostProps = {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Component } from 'solid-js';
|
import { Component } from 'solid-js';
|
||||||
|
|
||||||
import { nip19 } from 'nostr-tools';
|
import { nip19 } from 'nostr-tools';
|
||||||
|
|
||||||
const { noteEncode } = nip19;
|
const { noteEncode } = nip19;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const Modal: Component<ModalProps> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
class="absolute top-0 left-0 z-10 flex h-screen w-screen cursor-default place-content-center place-items-center bg-black/30"
|
class="absolute top-0 left-0 z-10 flex h-screen w-screen cursor-default place-content-center place-items-center bg-black/30"
|
||||||
|
|||||||
@@ -8,25 +8,22 @@ import {
|
|||||||
type JSX,
|
type JSX,
|
||||||
type Accessor,
|
type Accessor,
|
||||||
} from 'solid-js';
|
} from 'solid-js';
|
||||||
import { createMutation } from '@tanstack/solid-query';
|
|
||||||
import { Event as NostrEvent } from 'nostr-tools';
|
|
||||||
import uniq from 'lodash/uniq';
|
|
||||||
|
|
||||||
import PaperAirplane from 'heroicons/24/solid/paper-airplane.svg';
|
import { createMutation } from '@tanstack/solid-query';
|
||||||
import Photo from 'heroicons/24/outline/photo.svg';
|
import Photo from 'heroicons/24/outline/photo.svg';
|
||||||
import XMark from 'heroicons/24/outline/x-mark.svg';
|
import XMark from 'heroicons/24/outline/x-mark.svg';
|
||||||
|
import PaperAirplane from 'heroicons/24/solid/paper-airplane.svg';
|
||||||
|
import uniq from 'lodash/uniq';
|
||||||
|
import { Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import UserNameDisplay from '@/components/UserDisplayName';
|
import UserNameDisplay from '@/components/UserDisplayName';
|
||||||
|
|
||||||
import eventWrapper from '@/core/event';
|
import eventWrapper from '@/core/event';
|
||||||
|
|
||||||
import useConfig from '@/nostr/useConfig';
|
|
||||||
import useCommands, { PublishTextNoteParams } from '@/nostr/useCommands';
|
|
||||||
import usePubkey from '@/nostr/usePubkey';
|
|
||||||
import { useHandleCommand } from '@/hooks/useCommandBus';
|
|
||||||
|
|
||||||
import { uploadNostrBuild, uploadFiles } from '@/utils/imageUpload';
|
|
||||||
import parseTextNote from '@/core/parseTextNote';
|
import parseTextNote from '@/core/parseTextNote';
|
||||||
|
import { useHandleCommand } from '@/hooks/useCommandBus';
|
||||||
|
import useCommands, { PublishTextNoteParams } from '@/nostr/useCommands';
|
||||||
|
import useConfig from '@/nostr/useConfig';
|
||||||
|
import usePubkey from '@/nostr/usePubkey';
|
||||||
|
import { uploadNostrBuild, uploadFiles } from '@/utils/imageUpload';
|
||||||
|
|
||||||
type NotePostFormProps = {
|
type NotePostFormProps = {
|
||||||
replyTo?: NostrEvent;
|
replyTo?: NostrEvent;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { For, Switch, Match, type Component } from 'solid-js';
|
import { For, Switch, Match, type Component } from 'solid-js';
|
||||||
|
|
||||||
import { Kind, type Event as NostrEvent } from 'nostr-tools';
|
import { Kind, type Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import TextNote from '@/components/TextNote';
|
|
||||||
import Reaction from '@/components/notification/Reaction';
|
|
||||||
import DeprecatedRepost from '@/components/DeprecatedRepost';
|
import DeprecatedRepost from '@/components/DeprecatedRepost';
|
||||||
|
import Reaction from '@/components/notification/Reaction';
|
||||||
|
import TextNote from '@/components/TextNote';
|
||||||
|
|
||||||
export type NotificationProps = {
|
export type NotificationProps = {
|
||||||
events: NostrEvent[];
|
events: NostrEvent[];
|
||||||
|
|||||||
@@ -1,31 +1,30 @@
|
|||||||
import { Component, createSignal, createMemo, Show, Switch, Match, createEffect } from 'solid-js';
|
import { Component, createSignal, createMemo, Show, Switch, Match, createEffect } from 'solid-js';
|
||||||
import { createMutation } from '@tanstack/solid-query';
|
|
||||||
|
|
||||||
|
import { createMutation } from '@tanstack/solid-query';
|
||||||
|
import ArrowPath from 'heroicons/24/outline/arrow-path.svg';
|
||||||
|
import EllipsisHorizontal from 'heroicons/24/outline/ellipsis-horizontal.svg';
|
||||||
import GlobeAlt from 'heroicons/24/outline/globe-alt.svg';
|
import GlobeAlt from 'heroicons/24/outline/globe-alt.svg';
|
||||||
import XMark from 'heroicons/24/outline/x-mark.svg';
|
import XMark from 'heroicons/24/outline/x-mark.svg';
|
||||||
import CheckCircle from 'heroicons/24/solid/check-circle.svg';
|
import CheckCircle from 'heroicons/24/solid/check-circle.svg';
|
||||||
import ExclamationCircle from 'heroicons/24/solid/exclamation-circle.svg';
|
import ExclamationCircle from 'heroicons/24/solid/exclamation-circle.svg';
|
||||||
import ArrowPath from 'heroicons/24/outline/arrow-path.svg';
|
|
||||||
import EllipsisHorizontal from 'heroicons/24/outline/ellipsis-horizontal.svg';
|
|
||||||
|
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import Timeline from '@/components/Timeline';
|
import Timeline from '@/components/Timeline';
|
||||||
import Copy from '@/components/utils/Copy';
|
import Copy from '@/components/utils/Copy';
|
||||||
import SafeLink from '@/components/utils/SafeLink';
|
import SafeLink from '@/components/utils/SafeLink';
|
||||||
|
|
||||||
import usePubkey from '@/nostr/usePubkey';
|
|
||||||
import useProfile from '@/nostr/useProfile';
|
|
||||||
import useVerification from '@/nostr/useVerification';
|
|
||||||
import useFollowings from '@/nostr/useFollowings';
|
|
||||||
import useFollowers from '@/nostr/useFollowers';
|
|
||||||
import useConfig from '@/nostr/useConfig';
|
|
||||||
import useCommands from '@/nostr/useCommands';
|
import useCommands from '@/nostr/useCommands';
|
||||||
|
import useConfig from '@/nostr/useConfig';
|
||||||
|
import useFollowers from '@/nostr/useFollowers';
|
||||||
|
import useFollowings from '@/nostr/useFollowings';
|
||||||
|
import useProfile from '@/nostr/useProfile';
|
||||||
|
import usePubkey from '@/nostr/usePubkey';
|
||||||
import useSubscription from '@/nostr/useSubscription';
|
import useSubscription from '@/nostr/useSubscription';
|
||||||
|
import useVerification from '@/nostr/useVerification';
|
||||||
import npubEncodeFallback from '@/utils/npubEncodeFallback';
|
|
||||||
import ensureNonNull from '@/utils/ensureNonNull';
|
import ensureNonNull from '@/utils/ensureNonNull';
|
||||||
import epoch from '@/utils/epoch';
|
import epoch from '@/utils/epoch';
|
||||||
|
import npubEncodeFallback from '@/utils/npubEncodeFallback';
|
||||||
import timeout from '@/utils/timeout';
|
import timeout from '@/utils/timeout';
|
||||||
|
|
||||||
import ContextMenu, { MenuItem } from './ContextMenu';
|
import ContextMenu, { MenuItem } from './ContextMenu';
|
||||||
|
|
||||||
export type ProfileDisplayProps = {
|
export type ProfileDisplayProps = {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { createSignal, Show, type JSX, Component } from 'solid-js';
|
import { createSignal, Show, type JSX, Component } from 'solid-js';
|
||||||
|
|
||||||
|
import Cog6Tooth from 'heroicons/24/outline/cog-6-tooth.svg';
|
||||||
import MagnifyingGlass from 'heroicons/24/solid/magnifying-glass.svg';
|
import MagnifyingGlass from 'heroicons/24/solid/magnifying-glass.svg';
|
||||||
import PencilSquare from 'heroicons/24/solid/pencil-square.svg';
|
import PencilSquare from 'heroicons/24/solid/pencil-square.svg';
|
||||||
import Cog6Tooth from 'heroicons/24/outline/cog-6-tooth.svg';
|
|
||||||
|
|
||||||
import NotePostForm from '@/components/NotePostForm';
|
|
||||||
import Config from '@/components/Config';
|
import Config from '@/components/Config';
|
||||||
|
import NotePostForm from '@/components/NotePostForm';
|
||||||
import { useHandleCommand } from '@/hooks/useCommandBus';
|
import { useHandleCommand } from '@/hooks/useCommandBus';
|
||||||
import useConfig from '@/nostr/useConfig';
|
import useConfig from '@/nostr/useConfig';
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Show, type Component } from 'solid-js';
|
|||||||
|
|
||||||
import ColumnItem from '@/components/ColumnItem';
|
import ColumnItem from '@/components/ColumnItem';
|
||||||
import useConfig from '@/nostr/useConfig';
|
import useConfig from '@/nostr/useConfig';
|
||||||
|
|
||||||
import TextNoteDisplay, { TextNoteDisplayProps } from './textNote/TextNoteDisplay';
|
import TextNoteDisplay, { TextNoteDisplayProps } from './textNote/TextNoteDisplay';
|
||||||
|
|
||||||
export type TextNoteProps = TextNoteDisplayProps;
|
export type TextNoteProps = TextNoteDisplayProps;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { For, Switch, Match, type Component } from 'solid-js';
|
import { For, Switch, Match, type Component } from 'solid-js';
|
||||||
|
|
||||||
import { Kind, type Event as NostrEvent } from 'nostr-tools';
|
import { Kind, type Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import TextNote from '@/components/TextNote';
|
|
||||||
import DeprecatedRepost from '@/components/DeprecatedRepost';
|
import DeprecatedRepost from '@/components/DeprecatedRepost';
|
||||||
|
import TextNote from '@/components/TextNote';
|
||||||
|
|
||||||
export type TimelineProps = {
|
export type TimelineProps = {
|
||||||
events: NostrEvent[];
|
events: NostrEvent[];
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { Switch, Match, type Component } from 'solid-js';
|
import { Switch, Match, type Component } from 'solid-js';
|
||||||
import { Filter, Event as NostrEvent } from 'nostr-tools';
|
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
|
import { Filter, Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import useConfig from '@/nostr/useConfig';
|
|
||||||
|
|
||||||
import { type TimelineContent } from '@/components/TimelineContext';
|
|
||||||
import Timeline from '@/components/Timeline';
|
import Timeline from '@/components/Timeline';
|
||||||
import useSubscription from '@/nostr/useSubscription';
|
import { type TimelineContent } from '@/components/TimelineContext';
|
||||||
import eventWrapper from '@/core/event';
|
import eventWrapper from '@/core/event';
|
||||||
|
import useConfig from '@/nostr/useConfig';
|
||||||
|
import useSubscription from '@/nostr/useSubscription';
|
||||||
|
|
||||||
const relatedEvents = (rawEvent: NostrEvent) => {
|
const relatedEvents = (rawEvent: NostrEvent) => {
|
||||||
const event = () => eventWrapper(rawEvent);
|
const event = () => eventWrapper(rawEvent);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { createContext, useContext } from 'solid-js';
|
import { createContext, useContext } from 'solid-js';
|
||||||
import { createStore } from 'solid-js/store';
|
|
||||||
import { Event as NostrEvent } from 'nostr-tools';
|
import { Event as NostrEvent } from 'nostr-tools';
|
||||||
|
import { createStore } from 'solid-js/store';
|
||||||
|
|
||||||
export type TimelineContent = {
|
export type TimelineContent = {
|
||||||
type: 'Replies';
|
type: 'Replies';
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Switch, Match, type Component, Show } from 'solid-js';
|
import { Switch, Match, type Component, Show } from 'solid-js';
|
||||||
import { type Event as NostrEvent } from 'nostr-tools';
|
|
||||||
import HeartSolid from 'heroicons/24/solid/heart.svg';
|
import HeartSolid from 'heroicons/24/solid/heart.svg';
|
||||||
|
import { type Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import ColumnItem from '@/components/ColumnItem';
|
import ColumnItem from '@/components/ColumnItem';
|
||||||
import TextNoteDisplay from '@/components/textNote/TextNoteDisplay';
|
import TextNoteDisplay from '@/components/textNote/TextNoteDisplay';
|
||||||
import UserDisplayName from '@/components/UserDisplayName';
|
import UserDisplayName from '@/components/UserDisplayName';
|
||||||
|
|
||||||
import useProfile from '@/nostr/useProfile';
|
|
||||||
import useEvent from '@/nostr/useEvent';
|
|
||||||
import eventWrapper from '@/core/event';
|
import eventWrapper from '@/core/event';
|
||||||
import useModalState from '@/hooks/useModalState';
|
import useModalState from '@/hooks/useModalState';
|
||||||
|
import useEvent from '@/nostr/useEvent';
|
||||||
|
import useProfile from '@/nostr/useProfile';
|
||||||
|
|
||||||
type ReactionProps = {
|
type ReactionProps = {
|
||||||
event: NostrEvent;
|
event: NostrEvent;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createSignal, type Component, type JSX, Show } from 'solid-js';
|
import { createSignal, type Component, type JSX, Show } from 'solid-js';
|
||||||
|
|
||||||
import { ContentWarning } from '@/core/event';
|
import { ContentWarning } from '@/core/event';
|
||||||
|
|
||||||
export type ContentWarningDisplayProps = {
|
export type ContentWarningDisplayProps = {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { Component, createEffect, createSignal, onMount, Show, JSX } from 'solid-js';
|
import { Component, createSignal, Show } from 'solid-js';
|
||||||
|
|
||||||
import { fixUrl } from '@/utils/imageUrl';
|
import { fixUrl } from '@/utils/imageUrl';
|
||||||
|
|
||||||
import SafeLink from '../utils/SafeLink';
|
import SafeLink from '../utils/SafeLink';
|
||||||
|
|
||||||
type ImageDisplayProps = {
|
type ImageDisplayProps = {
|
||||||
@@ -14,12 +16,13 @@ const ImageDisplay: Component<ImageDisplayProps> = (props) => {
|
|||||||
const [hidden, setHidden] = createSignal(props.initialHidden);
|
const [hidden, setHidden] = createSignal(props.initialHidden);
|
||||||
const [playing, setPlaying] = createSignal(true);
|
const [playing, setPlaying] = createSignal(true);
|
||||||
|
|
||||||
const isGIF = () => props.url.match(/\.gif/i);
|
// const isGIF = () => props.url.match(/\.gif/i);
|
||||||
|
|
||||||
const play = () => {
|
const play = () => {
|
||||||
setPlaying(true);
|
setPlaying(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
const stop = () => {
|
const stop = () => {
|
||||||
if (canvasRef == null || imageRef == null) return;
|
if (canvasRef == null || imageRef == null) return;
|
||||||
canvasRef.width = imageRef.width;
|
canvasRef.width = imageRef.width;
|
||||||
@@ -39,6 +42,7 @@ const ImageDisplay: Component<ImageDisplayProps> = (props) => {
|
|||||||
);
|
);
|
||||||
setPlaying(false);
|
setPlaying(false);
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show
|
<Show
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Show } from 'solid-js';
|
import { Show } from 'solid-js';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-cycle
|
||||||
import TextNoteDisplayById from '@/components/textNote/TextNoteDisplayById';
|
import TextNoteDisplayById from '@/components/textNote/TextNoteDisplayById';
|
||||||
import { type MentionedEvent } from '@/core/parseTextNote';
|
import { type MentionedEvent } from '@/core/parseTextNote';
|
||||||
|
|
||||||
import EventLink from '../EventLink';
|
import EventLink from '../EventLink';
|
||||||
|
|
||||||
export type MentionedEventDisplayProps = {
|
export type MentionedEventDisplayProps = {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import type { MentionedUser } from '@/core/parseTextNote';
|
|
||||||
import GeneralUserMentionDisplay from '@/components/textNote/GeneralUserMentionDisplay';
|
import GeneralUserMentionDisplay from '@/components/textNote/GeneralUserMentionDisplay';
|
||||||
import useModalState from '@/hooks/useModalState';
|
import useModalState from '@/hooks/useModalState';
|
||||||
|
|
||||||
|
import type { MentionedUser } from '@/core/parseTextNote';
|
||||||
|
|
||||||
export type MentionedUserDisplayProps = {
|
export type MentionedUserDisplayProps = {
|
||||||
pubkey: string;
|
pubkey: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
import { For } from 'solid-js';
|
import { For } from 'solid-js';
|
||||||
import parseTextNote, { resolveTagReference, type ParsedTextNoteNode } from '@/core/parseTextNote';
|
|
||||||
import type { Event as NostrEvent } from 'nostr-tools';
|
import EventLink from '@/components/EventLink';
|
||||||
import PlainTextDisplay from '@/components/textNote/PlainTextDisplay';
|
import ImageDisplay from '@/components/textNote/ImageDisplay';
|
||||||
import MentionedUserDisplay from '@/components/textNote/MentionedUserDisplay';
|
|
||||||
// eslint-disable-next-line import/no-cycle
|
// eslint-disable-next-line import/no-cycle
|
||||||
import MentionedEventDisplay from '@/components/textNote/MentionedEventDisplay';
|
import MentionedEventDisplay from '@/components/textNote/MentionedEventDisplay';
|
||||||
import ImageDisplay from '@/components/textNote/ImageDisplay';
|
import MentionedUserDisplay from '@/components/textNote/MentionedUserDisplay';
|
||||||
|
import PlainTextDisplay from '@/components/textNote/PlainTextDisplay';
|
||||||
|
import TextNoteDisplayById from '@/components/textNote/TextNoteDisplayById';
|
||||||
import SafeLink from '@/components/utils/SafeLink';
|
import SafeLink from '@/components/utils/SafeLink';
|
||||||
import eventWrapper from '@/core/event';
|
import eventWrapper from '@/core/event';
|
||||||
import { isImageUrl } from '@/utils/imageUrl';
|
import parseTextNote, { resolveTagReference, type ParsedTextNoteNode } from '@/core/parseTextNote';
|
||||||
|
|
||||||
|
import type { Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import useConfig from '@/nostr/useConfig';
|
import useConfig from '@/nostr/useConfig';
|
||||||
import EventLink from '../EventLink';
|
import { isImageUrl } from '@/utils/imageUrl';
|
||||||
import TextNoteDisplayById from './TextNoteDisplayById';
|
|
||||||
|
|
||||||
export type TextNoteContentDisplayProps = {
|
export type TextNoteContentDisplayProps = {
|
||||||
event: NostrEvent;
|
event: NostrEvent;
|
||||||
|
|||||||
@@ -1,36 +1,33 @@
|
|||||||
import { Show, For, createSignal, createMemo, onMount, type JSX, type Component } from 'solid-js';
|
import { Show, For, createSignal, createMemo, onMount, type JSX, type Component } from 'solid-js';
|
||||||
import { nip19, type Event as NostrEvent } from 'nostr-tools';
|
|
||||||
import { createMutation } from '@tanstack/solid-query';
|
|
||||||
|
|
||||||
import HeartOutlined from 'heroicons/24/outline/heart.svg';
|
import { createMutation } from '@tanstack/solid-query';
|
||||||
import HeartSolid from 'heroicons/24/solid/heart.svg';
|
|
||||||
import ArrowPathRoundedSquare from 'heroicons/24/outline/arrow-path-rounded-square.svg';
|
import ArrowPathRoundedSquare from 'heroicons/24/outline/arrow-path-rounded-square.svg';
|
||||||
import ChatBubbleLeft from 'heroicons/24/outline/chat-bubble-left.svg';
|
import ChatBubbleLeft from 'heroicons/24/outline/chat-bubble-left.svg';
|
||||||
import EllipsisHorizontal from 'heroicons/24/outline/ellipsis-horizontal.svg';
|
import EllipsisHorizontal from 'heroicons/24/outline/ellipsis-horizontal.svg';
|
||||||
|
import HeartOutlined from 'heroicons/24/outline/heart.svg';
|
||||||
|
import HeartSolid from 'heroicons/24/solid/heart.svg';
|
||||||
|
import { nip19, type Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import eventWrapper from '@/core/event';
|
import NotePostForm from '@/components/NotePostForm';
|
||||||
|
import ContentWarningDisplay from '@/components/textNote/ContentWarningDisplay';
|
||||||
import useProfile from '@/nostr/useProfile';
|
import GeneralUserMentionDisplay from '@/components/textNote/GeneralUserMentionDisplay';
|
||||||
import useConfig from '@/nostr/useConfig';
|
// eslint-disable-next-line import/no-cycle
|
||||||
import usePubkey from '@/nostr/usePubkey';
|
import TextNoteContentDisplay from '@/components/textNote/TextNoteContentDisplay';
|
||||||
import useCommands from '@/nostr/useCommands';
|
|
||||||
import useReactions from '@/nostr/useReactions';
|
|
||||||
import useDeprecatedReposts from '@/nostr/useDeprecatedReposts';
|
|
||||||
|
|
||||||
import useFormatDate from '@/hooks/useFormatDate';
|
|
||||||
import useModalState from '@/hooks/useModalState';
|
|
||||||
|
|
||||||
import UserNameDisplay from '@/components/UserDisplayName';
|
|
||||||
import TextNoteDisplayById from '@/components/textNote/TextNoteDisplayById';
|
import TextNoteDisplayById from '@/components/textNote/TextNoteDisplayById';
|
||||||
import { useTimelineContext } from '@/components/TimelineContext';
|
import { useTimelineContext } from '@/components/TimelineContext';
|
||||||
import GeneralUserMentionDisplay from '@/components/textNote/GeneralUserMentionDisplay';
|
import eventWrapper from '@/core/event';
|
||||||
import ContentWarningDisplay from '@/components/textNote/ContentWarningDisplay';
|
import useFormatDate from '@/hooks/useFormatDate';
|
||||||
import TextNoteContentDisplay from '@/components/textNote/TextNoteContentDisplay';
|
import useModalState from '@/hooks/useModalState';
|
||||||
import NotePostForm from '@/components/NotePostForm';
|
import useCommands from '@/nostr/useCommands';
|
||||||
|
import useConfig from '@/nostr/useConfig';
|
||||||
|
import useProfile from '@/nostr/useProfile';
|
||||||
|
import usePubkey from '@/nostr/usePubkey';
|
||||||
|
import useReactions from '@/nostr/useReactions';
|
||||||
|
import useReposts from '@/nostr/useReposts';
|
||||||
|
import useSubscription from '@/nostr/useSubscription';
|
||||||
import ensureNonNull from '@/utils/ensureNonNull';
|
import ensureNonNull from '@/utils/ensureNonNull';
|
||||||
import npubEncodeFallback from '@/utils/npubEncodeFallback';
|
import npubEncodeFallback from '@/utils/npubEncodeFallback';
|
||||||
import useSubscription from '@/nostr/useSubscription';
|
|
||||||
import ContextMenu, { MenuItem } from '../ContextMenu';
|
import ContextMenu, { MenuItem } from '../ContextMenu';
|
||||||
|
|
||||||
export type TextNoteDisplayProps = {
|
export type TextNoteDisplayProps = {
|
||||||
@@ -85,7 +82,7 @@ const TextNoteDisplay: Component<TextNoteDisplayProps> = (props) => {
|
|||||||
eventId: props.event.id,
|
eventId: props.event.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { reposts, isRepostedBy, invalidateDeprecatedReposts } = useDeprecatedReposts(() => ({
|
const { reposts, isRepostedBy, invalidateReposts } = useReposts(() => ({
|
||||||
eventId: props.event.id,
|
eventId: props.event.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -105,9 +102,9 @@ const TextNoteDisplay: Component<TextNoteDisplayProps> = (props) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const publishDeprecatedRepostMutation = createMutation({
|
const publishRepostMutation = createMutation({
|
||||||
mutationKey: ['publishDeprecatedRepost', event().id],
|
mutationKey: ['publishRepost', event().id],
|
||||||
mutationFn: commands.publishDeprecatedRepost.bind(commands),
|
mutationFn: commands.publishRepost.bind(commands),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
console.log('succeeded to publish reposts');
|
console.log('succeeded to publish reposts');
|
||||||
},
|
},
|
||||||
@@ -115,7 +112,7 @@ const TextNoteDisplay: Component<TextNoteDisplayProps> = (props) => {
|
|||||||
console.error('failed to publish repost: ', err);
|
console.error('failed to publish repost: ', err);
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
invalidateDeprecatedReposts().catch((err) => console.error('failed to refetch reposts', err));
|
invalidateReposts().catch((err) => console.error('failed to refetch reposts', err));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,7 +148,7 @@ const TextNoteDisplay: Component<TextNoteDisplayProps> = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ensureNonNull([pubkey(), props.event.id] as const)(([pubkeyNonNull, eventIdNonNull]) => {
|
ensureNonNull([pubkey(), props.event.id] as const)(([pubkeyNonNull, eventIdNonNull]) => {
|
||||||
publishDeprecatedRepostMutation.mutate({
|
publishRepostMutation.mutate({
|
||||||
relayUrls: config().relayUrls,
|
relayUrls: config().relayUrls,
|
||||||
pubkey: pubkeyNonNull,
|
pubkey: pubkeyNonNull,
|
||||||
eventId: eventIdNonNull,
|
eventId: eventIdNonNull,
|
||||||
@@ -306,13 +303,13 @@ const TextNoteDisplay: Component<TextNoteDisplayProps> = (props) => {
|
|||||||
class="flex shrink-0 items-center gap-1"
|
class="flex shrink-0 items-center gap-1"
|
||||||
classList={{
|
classList={{
|
||||||
'text-zinc-400': !isRepostedByMe(),
|
'text-zinc-400': !isRepostedByMe(),
|
||||||
'text-green-400': isRepostedByMe() || publishDeprecatedRepostMutation.isLoading,
|
'text-green-400': isRepostedByMe() || publishRepostMutation.isLoading,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="h-4 w-4"
|
class="h-4 w-4"
|
||||||
onClick={handleRepost}
|
onClick={handleRepost}
|
||||||
disabled={publishDeprecatedRepostMutation.isLoading}
|
disabled={publishRepostMutation.isLoading}
|
||||||
>
|
>
|
||||||
<ArrowPathRoundedSquare />
|
<ArrowPathRoundedSquare />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import { Switch, Match, type Component } from 'solid-js';
|
|||||||
|
|
||||||
// eslint-disable-next-line import/no-cycle
|
// eslint-disable-next-line import/no-cycle
|
||||||
import TextNoteDisplay, { type TextNoteDisplayProps } from '@/components/textNote/TextNoteDisplay';
|
import TextNoteDisplay, { type TextNoteDisplayProps } from '@/components/textNote/TextNoteDisplay';
|
||||||
|
|
||||||
import useConfig from '@/nostr/useConfig';
|
import useConfig from '@/nostr/useConfig';
|
||||||
import useEvent from '@/nostr/useEvent';
|
import useEvent from '@/nostr/useEvent';
|
||||||
|
|
||||||
import ensureNonNull from '@/utils/ensureNonNull';
|
import ensureNonNull from '@/utils/ensureNonNull';
|
||||||
|
|
||||||
import EventLink from '../EventLink';
|
import EventLink from '../EventLink';
|
||||||
|
|
||||||
type TextNoteDisplayByIdProps = Omit<TextNoteDisplayProps, 'event'> & {
|
type TextNoteDisplayByIdProps = Omit<TextNoteDisplayProps, 'event'> & {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// import { z } from 'zod';
|
// import { z } from 'zod';
|
||||||
import { type Filter } from 'nostr-tools';
|
import { type Filter } from 'nostr-tools';
|
||||||
|
|
||||||
import { type ColumnProps } from '@/components/Column';
|
import { type ColumnProps } from '@/components/Column';
|
||||||
|
|
||||||
export type NotificationType =
|
export type NotificationType =
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Event as NostrEvent } from 'nostr-tools';
|
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
|
|
||||||
|
import type { Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
export type EventMarker = 'reply' | 'root' | 'mention';
|
export type EventMarker = 'reply' | 'root' | 'mention';
|
||||||
|
|
||||||
export type TaggedEvent = {
|
export type TaggedEvent = {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { describe, it } from 'vitest';
|
|
||||||
import { type Event as NostrEvent } from 'nostr-tools';
|
import { type Event as NostrEvent } from 'nostr-tools';
|
||||||
|
import { describe, it } from 'vitest';
|
||||||
|
|
||||||
import parseTextNote, {
|
import parseTextNote, {
|
||||||
resolveTagReference,
|
resolveTagReference,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { nip19, type Event as NostrEvent } from 'nostr-tools';
|
import { nip19, type Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
import eventWrapper from './event';
|
import eventWrapper from './event';
|
||||||
|
|
||||||
type ProfilePointer = nip19.ProfilePointer;
|
type ProfilePointer = nip19.ProfilePointer;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createSignal, createEffect, onMount, type Signal } from 'solid-js';
|
import { createSignal, createEffect, onMount, type Signal } from 'solid-js';
|
||||||
|
|
||||||
import { createStore, SetStoreFunction, type Store, type StoreNode } from 'solid-js/store';
|
import { createStore, SetStoreFunction, type Store, type StoreNode } from 'solid-js/store';
|
||||||
|
|
||||||
type GenericStorage<T> = {
|
type GenericStorage<T> = {
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import useConfig from '@/nostr/useConfig';
|
|
||||||
|
|
||||||
import useDatePulser from '@/hooks/useDatePulser';
|
import useDatePulser from '@/hooks/useDatePulser';
|
||||||
|
import useConfig from '@/nostr/useConfig';
|
||||||
import { formatRelative, formatAbsoluteLong, formatAbsoluteShort } from '@/utils/formatDate';
|
import { formatRelative, formatAbsoluteLong, formatAbsoluteShort } from '@/utils/formatDate';
|
||||||
|
|
||||||
// 7 seconds is used here so that the last digit of relative time is changed.
|
// 7 seconds is used here so that the last digit of relative time is changed.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Accessor } from 'solid-js';
|
import { Accessor } from 'solid-js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createSignalWithStorage,
|
createSignalWithStorage,
|
||||||
createStorageWithSerializer,
|
createStorageWithSerializer,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Accessor } from 'solid-js';
|
|
||||||
import { createSignal, createEffect } from 'solid-js';
|
import { createSignal, createEffect } from 'solid-js';
|
||||||
|
import type { Accessor } from 'solid-js';
|
||||||
|
|
||||||
export type UseResizedImageProps = {
|
export type UseResizedImageProps = {
|
||||||
imageUrl: Accessor<string | undefined>;
|
imageUrl: Accessor<string | undefined>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// type Commands = (typeof commands)[number];
|
// type Commands = (typeof commands)[number];
|
||||||
|
|
||||||
import { onMount, onCleanup, type JSX } from 'solid-js';
|
import { onMount, onCleanup, type JSX } from 'solid-js';
|
||||||
|
|
||||||
import throttle from 'lodash/throttle';
|
import throttle from 'lodash/throttle';
|
||||||
|
|
||||||
import { useRequestCommand, type Command } from '@/hooks/useCommandBus';
|
import { useRequestCommand, type Command } from '@/hooks/useCommandBus';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* @refresh reload */
|
/* @refresh reload */
|
||||||
import { render } from 'solid-js/web';
|
|
||||||
import { Router } from '@solidjs/router';
|
import { Router } from '@solidjs/router';
|
||||||
|
import { render } from 'solid-js/web';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export type Task<TaskArgs, TaskResult> = {
|
|||||||
id: number;
|
id: number;
|
||||||
args: TaskArgs;
|
args: TaskArgs;
|
||||||
resolve: (result: TaskResult) => void;
|
resolve: (result: TaskResult) => void;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
reject: (error: any) => void;
|
reject: (error: any) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -16,11 +17,13 @@ export type UseBatchProps<TaskArgs, TaskResult> = {
|
|||||||
export type PromiseWithCallbacks<T> = {
|
export type PromiseWithCallbacks<T> = {
|
||||||
promise: Promise<T>;
|
promise: Promise<T>;
|
||||||
resolve: (e: T) => void;
|
resolve: (e: T) => void;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
reject: (e: any) => void;
|
reject: (e: any) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const promiseWithCallbacks = <T>(): PromiseWithCallbacks<T> => {
|
const promiseWithCallbacks = <T>(): PromiseWithCallbacks<T> => {
|
||||||
let resolve: ((e: T) => void) | undefined;
|
let resolve: ((e: T) => void) | undefined;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
let reject: ((e: any) => void) | undefined;
|
let reject: ((e: any) => void) | undefined;
|
||||||
|
|
||||||
const promise = new Promise<T>((resolveFn, rejectFn) => {
|
const promise = new Promise<T>((resolveFn, rejectFn) => {
|
||||||
|
|||||||
@@ -6,23 +6,23 @@ import {
|
|||||||
type Accessor,
|
type Accessor,
|
||||||
type Signal,
|
type Signal,
|
||||||
} from 'solid-js';
|
} from 'solid-js';
|
||||||
import { type Event as NostrEvent, type Filter, Kind } from 'nostr-tools';
|
|
||||||
import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query';
|
import { createQuery, useQueryClient, type CreateQueryResult } from '@tanstack/solid-query';
|
||||||
|
import { type Event as NostrEvent, type Filter, Kind } from 'nostr-tools';
|
||||||
|
|
||||||
import eventWrapper from '@/core/event';
|
import eventWrapper from '@/core/event';
|
||||||
|
|
||||||
import useBatch, { type Task } from '@/nostr/useBatch';
|
import useBatch, { type Task } from '@/nostr/useBatch';
|
||||||
import useStats from '@/nostr/useStats';
|
|
||||||
import useConfig from '@/nostr/useConfig';
|
import useConfig from '@/nostr/useConfig';
|
||||||
import usePool from '@/nostr/usePool';
|
import usePool from '@/nostr/usePool';
|
||||||
|
import useStats from '@/nostr/useStats';
|
||||||
import timeout from '@/utils/timeout';
|
import timeout from '@/utils/timeout';
|
||||||
|
|
||||||
type TaskArg =
|
type TaskArg =
|
||||||
| { type: 'Profile'; pubkey: string }
|
| { type: 'Profile'; pubkey: string }
|
||||||
| { type: 'TextNote'; eventId: string }
|
| { type: 'TextNote'; eventId: string }
|
||||||
| { type: 'Reactions'; mentionedEventId: string }
|
| { type: 'Reactions'; mentionedEventId: string }
|
||||||
| { type: 'DeprecatedReposts'; mentionedEventId: string }
|
| { type: 'ZapReceipts'; mentionedEventId: string }
|
||||||
|
| { type: 'Reposts'; mentionedEventId: string }
|
||||||
| { type: 'Followings'; pubkey: string };
|
| { type: 'Followings'; pubkey: string };
|
||||||
|
|
||||||
type BatchedEvents = { completed: boolean; events: NostrEvent[] };
|
type BatchedEvents = { completed: boolean; events: NostrEvent[] };
|
||||||
@@ -83,15 +83,15 @@ export type UseReactions = {
|
|||||||
query: CreateQueryResult<NostrEvent[]>;
|
query: CreateQueryResult<NostrEvent[]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// DeprecatedReposts
|
// Reposts
|
||||||
export type UseDeprecatedRepostsProps = {
|
export type UseRepostsProps = {
|
||||||
eventId: string;
|
eventId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UseDeprecatedReposts = {
|
export type UseReposts = {
|
||||||
reposts: () => NostrEvent[];
|
reposts: () => NostrEvent[];
|
||||||
isRepostedBy: (pubkey: string) => boolean;
|
isRepostedBy: (pubkey: string) => boolean;
|
||||||
invalidateDeprecatedReposts: () => Promise<void>;
|
invalidateReposts: () => Promise<void>;
|
||||||
query: CreateQueryResult<NostrEvent[]>;
|
query: CreateQueryResult<NostrEvent[]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ setInterval(() => {
|
|||||||
setActiveBatchSubscriptions(count);
|
setActiveBatchSubscriptions(count);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
const EmptyBatchedEvents = Object.freeze({ events: Object.freeze([]), completed: true });
|
const EmptyBatchedEvents = { events: [], completed: true };
|
||||||
const emptyBatchedEvents = () => EmptyBatchedEvents;
|
const emptyBatchedEvents = () => EmptyBatchedEvents;
|
||||||
|
|
||||||
const { exec } = useBatch<TaskArg, TaskRes>(() => ({
|
const { exec } = useBatch<TaskArg, TaskRes>(() => ({
|
||||||
@@ -132,6 +132,7 @@ const { exec } = useBatch<TaskArg, TaskRes>(() => ({
|
|||||||
const textNoteTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
const textNoteTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
||||||
const reactionsTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
const reactionsTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
||||||
const repostsTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
const repostsTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
||||||
|
const zapReceiptsTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
||||||
const followingsTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
const followingsTasks = new Map<string, Task<TaskArg, TaskRes>[]>();
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
tasks.forEach((task) => {
|
||||||
@@ -144,9 +145,12 @@ const { exec } = useBatch<TaskArg, TaskRes>(() => ({
|
|||||||
} else if (task.args.type === 'Reactions') {
|
} else if (task.args.type === 'Reactions') {
|
||||||
const current = reactionsTasks.get(task.args.mentionedEventId) ?? [];
|
const current = reactionsTasks.get(task.args.mentionedEventId) ?? [];
|
||||||
reactionsTasks.set(task.args.mentionedEventId, [...current, task]);
|
reactionsTasks.set(task.args.mentionedEventId, [...current, task]);
|
||||||
} else if (task.args.type === 'DeprecatedReposts') {
|
} else if (task.args.type === 'Reposts') {
|
||||||
const current = repostsTasks.get(task.args.mentionedEventId) ?? [];
|
const current = repostsTasks.get(task.args.mentionedEventId) ?? [];
|
||||||
repostsTasks.set(task.args.mentionedEventId, [...current, task]);
|
repostsTasks.set(task.args.mentionedEventId, [...current, task]);
|
||||||
|
} else if (task.args.type === 'ZapReceipts') {
|
||||||
|
const current = zapReceiptsTasks.get(task.args.mentionedEventId) ?? [];
|
||||||
|
repostsTasks.set(task.args.mentionedEventId, [...current, task]);
|
||||||
} else if (task.args.type === 'Followings') {
|
} else if (task.args.type === 'Followings') {
|
||||||
const current = followingsTasks.get(task.args.pubkey) ?? [];
|
const current = followingsTasks.get(task.args.pubkey) ?? [];
|
||||||
followingsTasks.set(task.args.pubkey, [...current, task]);
|
followingsTasks.set(task.args.pubkey, [...current, task]);
|
||||||
@@ -157,6 +161,7 @@ const { exec } = useBatch<TaskArg, TaskRes>(() => ({
|
|||||||
const textNoteIds = [...textNoteTasks.keys()];
|
const textNoteIds = [...textNoteTasks.keys()];
|
||||||
const reactionsIds = [...reactionsTasks.keys()];
|
const reactionsIds = [...reactionsTasks.keys()];
|
||||||
const repostsIds = [...repostsTasks.keys()];
|
const repostsIds = [...repostsTasks.keys()];
|
||||||
|
const zapReceiptsIds = [...zapReceiptsTasks.keys()];
|
||||||
const followingsIds = [...followingsTasks.keys()];
|
const followingsIds = [...followingsTasks.keys()];
|
||||||
|
|
||||||
const filters: Filter[] = [];
|
const filters: Filter[] = [];
|
||||||
@@ -173,6 +178,9 @@ const { exec } = useBatch<TaskArg, TaskRes>(() => ({
|
|||||||
if (repostsIds.length > 0) {
|
if (repostsIds.length > 0) {
|
||||||
filters.push({ kinds: [6], '#e': repostsIds });
|
filters.push({ kinds: [6], '#e': repostsIds });
|
||||||
}
|
}
|
||||||
|
if (zapReceiptsIds.length > 0) {
|
||||||
|
filters.push({ kinds: [9735], '#e': zapReceiptsIds });
|
||||||
|
}
|
||||||
if (followingsIds.length > 0) {
|
if (followingsIds.length > 0) {
|
||||||
filters.push({ kinds: [Kind.Contacts], authors: followingsIds });
|
filters.push({ kinds: [Kind.Contacts], authors: followingsIds });
|
||||||
}
|
}
|
||||||
@@ -239,6 +247,13 @@ const { exec } = useBatch<TaskArg, TaskRes>(() => ({
|
|||||||
const registeredTasks = repostsTasks.get(taggedEventId) ?? [];
|
const registeredTasks = repostsTasks.get(taggedEventId) ?? [];
|
||||||
resolveTasks(registeredTasks, event);
|
resolveTasks(registeredTasks, event);
|
||||||
});
|
});
|
||||||
|
} else if (event.kind === Kind.Zap) {
|
||||||
|
const eventTags = eventWrapper(event).taggedEvents();
|
||||||
|
eventTags.forEach((eventTag) => {
|
||||||
|
const taggedEventId = eventTag.id;
|
||||||
|
const registeredTasks = repostsTasks.get(taggedEventId) ?? [];
|
||||||
|
resolveTasks(registeredTasks, event);
|
||||||
|
});
|
||||||
} else if (event.kind === Kind.Contacts) {
|
} else if (event.kind === Kind.Contacts) {
|
||||||
const registeredTasks = followingsTasks.get(event.pubkey) ?? [];
|
const registeredTasks = followingsTasks.get(event.pubkey) ?? [];
|
||||||
resolveTasks(registeredTasks, event);
|
resolveTasks(registeredTasks, event);
|
||||||
@@ -393,12 +408,10 @@ export const useReactions = (propsProvider: () => UseReactionsProps | null): Use
|
|||||||
return { reactions, reactionsGroupedByContent, isReactedBy, invalidateReactions, query };
|
return { reactions, reactionsGroupedByContent, isReactedBy, invalidateReactions, query };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDeprecatedReposts = (
|
export const useReposts = (propsProvider: () => UseRepostsProps): UseReposts => {
|
||||||
propsProvider: () => UseDeprecatedRepostsProps,
|
|
||||||
): UseDeprecatedReposts => {
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const props = createMemo(propsProvider);
|
const props = createMemo(propsProvider);
|
||||||
const genQueryKey = createMemo(() => ['useDeprecatedReposts', props()] as const);
|
const genQueryKey = createMemo(() => ['useReposts', props()] as const);
|
||||||
|
|
||||||
const query = createQuery(
|
const query = createQuery(
|
||||||
genQueryKey,
|
genQueryKey,
|
||||||
@@ -406,16 +419,14 @@ export const useDeprecatedReposts = (
|
|||||||
const [, currentProps] = queryKey;
|
const [, currentProps] = queryKey;
|
||||||
if (currentProps == null) return [];
|
if (currentProps == null) return [];
|
||||||
const { eventId: mentionedEventId } = currentProps;
|
const { eventId: mentionedEventId } = currentProps;
|
||||||
const promise = exec({ type: 'DeprecatedReposts', mentionedEventId }, signal).then(
|
const promise = exec({ type: 'Reposts', mentionedEventId }, signal).then((batchedEvents) => {
|
||||||
(batchedEvents) => {
|
|
||||||
const events = () => batchedEvents().events;
|
const events = () => batchedEvents().events;
|
||||||
observable(batchedEvents).subscribe(() => {
|
observable(batchedEvents).subscribe(() => {
|
||||||
queryClient.setQueryData(queryKey, events());
|
queryClient.setQueryData(queryKey, events());
|
||||||
});
|
});
|
||||||
return events();
|
return events();
|
||||||
},
|
});
|
||||||
);
|
return timeout(15000, `useReposts: ${mentionedEventId}`)(promise);
|
||||||
return timeout(15000, `useDeprecatedReposts: ${mentionedEventId}`)(promise);
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
staleTime: 1 * 60 * 1000, // 1 min
|
staleTime: 1 * 60 * 1000, // 1 min
|
||||||
@@ -429,10 +440,9 @@ export const useDeprecatedReposts = (
|
|||||||
const isRepostedBy = (pubkey: string): boolean =>
|
const isRepostedBy = (pubkey: string): boolean =>
|
||||||
reposts().findIndex((event) => event.pubkey === pubkey) !== -1;
|
reposts().findIndex((event) => event.pubkey === pubkey) !== -1;
|
||||||
|
|
||||||
const invalidateDeprecatedReposts = (): Promise<void> =>
|
const invalidateReposts = (): Promise<void> => queryClient.invalidateQueries(genQueryKey());
|
||||||
queryClient.invalidateQueries(genQueryKey());
|
|
||||||
|
|
||||||
return { reposts, isRepostedBy, invalidateDeprecatedReposts, query };
|
return { reposts, isRepostedBy, invalidateReposts, query };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useFollowings = (propsProvider: () => UseFollowingsProps | null): UseFollowings => {
|
export const useFollowings = (propsProvider: () => UseFollowingsProps | null): UseFollowings => {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
import { describe, it } from 'vitest';
|
import { describe, it } from 'vitest';
|
||||||
|
|
||||||
import { buildTags } from './useCommands';
|
import { buildTags } from './useCommands';
|
||||||
|
|
||||||
describe('buildTags', () => {
|
describe('buildTags', () => {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { getEventHash, Kind, type UnsignedEvent, type Pub } from 'nostr-tools';
|
|||||||
|
|
||||||
// import '@/types/nostr.d';
|
// import '@/types/nostr.d';
|
||||||
import usePool from '@/nostr/usePool';
|
import usePool from '@/nostr/usePool';
|
||||||
|
|
||||||
import epoch from '@/utils/epoch';
|
import epoch from '@/utils/epoch';
|
||||||
|
|
||||||
export type TagParams = {
|
export type TagParams = {
|
||||||
@@ -148,7 +147,7 @@ const useCommands = () => {
|
|||||||
return publishEvent(relayUrls, preSignedEvent);
|
return publishEvent(relayUrls, preSignedEvent);
|
||||||
},
|
},
|
||||||
// NIP-18
|
// NIP-18
|
||||||
async publishDeprecatedRepost({
|
async publishRepost({
|
||||||
relayUrls,
|
relayUrls,
|
||||||
pubkey,
|
pubkey,
|
||||||
eventId,
|
eventId,
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { type Accessor, type Setter } from 'solid-js';
|
import { type Accessor, type Setter } from 'solid-js';
|
||||||
|
|
||||||
import { Kind, type Event as NostrEvent } from 'nostr-tools';
|
import { Kind, type Event as NostrEvent } from 'nostr-tools';
|
||||||
|
|
||||||
|
import { ColumnConfig } from '@/core/column';
|
||||||
import {
|
import {
|
||||||
createStorageWithSerializer,
|
createStorageWithSerializer,
|
||||||
createStoreWithStorage,
|
createStoreWithStorage,
|
||||||
} from '@/hooks/createSignalWithStorage';
|
} from '@/hooks/createSignalWithStorage';
|
||||||
import { ColumnConfig } from '@/core/column';
|
|
||||||
|
|
||||||
export type Config = {
|
export type Config = {
|
||||||
relayUrls: string[];
|
relayUrls: string[];
|
||||||
@@ -111,7 +113,8 @@ const useConfig = (): UseConfig => {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const shouldMuteEvent = (event: NostrEvent) => isPubkeyMuted(event.pubkey) || hasMutedKeyword(event);
|
const shouldMuteEvent = (event: NostrEvent) =>
|
||||||
|
isPubkeyMuted(event.pubkey) || hasMutedKeyword(event);
|
||||||
|
|
||||||
const initializeColumns = ({ pubkey }: { pubkey: string }) => {
|
const initializeColumns = ({ pubkey }: { pubkey: string }) => {
|
||||||
// すでに設定されている場合は終了
|
// すでに設定されている場合は終了
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import { useDeprecatedReposts } from '@/nostr/useBatchedEvents';
|
|
||||||
|
|
||||||
export default useDeprecatedReposts;
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { createMemo, createSignal } from 'solid-js';
|
import { createMemo, createSignal } from 'solid-js';
|
||||||
import { Kind } from 'nostr-tools';
|
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
|
import { Kind } from 'nostr-tools';
|
||||||
|
|
||||||
import useConfig from '@/nostr/useConfig';
|
import useConfig from '@/nostr/useConfig';
|
||||||
import useSubscription from '@/nostr/useSubscription';
|
import useSubscription from '@/nostr/useSubscription';
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createSignal } from 'solid-js';
|
import { createSignal } from 'solid-js';
|
||||||
|
|
||||||
import { SimplePool } from 'nostr-tools';
|
import { SimplePool } from 'nostr-tools';
|
||||||
|
|
||||||
const [pool] = createSignal<SimplePool>(new SimplePool());
|
const [pool] = createSignal<SimplePool>(new SimplePool());
|
||||||
|
|||||||
3
src/nostr/useReposts.ts
Normal file
3
src/nostr/useReposts.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { useReposts } from '@/nostr/useBatchedEvents';
|
||||||
|
|
||||||
|
export default useReposts;
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
import { createSignal, createEffect, onCleanup, on } from 'solid-js';
|
import { createSignal, createEffect, onCleanup, on } from 'solid-js';
|
||||||
import type { Event as NostrEvent, Filter, SubscriptionOptions } from 'nostr-tools';
|
|
||||||
import uniqBy from 'lodash/uniqBy';
|
import uniqBy from 'lodash/uniqBy';
|
||||||
|
|
||||||
import usePool from '@/nostr/usePool';
|
import usePool from '@/nostr/usePool';
|
||||||
import useStats from './useStats';
|
|
||||||
import useConfig from './useConfig';
|
import useConfig from './useConfig';
|
||||||
|
import useStats from './useStats';
|
||||||
|
|
||||||
|
import type { Event as NostrEvent, Filter, SubscriptionOptions } from 'nostr-tools';
|
||||||
|
|
||||||
export type UseSubscriptionProps = {
|
export type UseSubscriptionProps = {
|
||||||
relayUrls: string[];
|
relayUrls: string[];
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createMemo, type Accessor } from 'solid-js';
|
import { createMemo, type Accessor } from 'solid-js';
|
||||||
|
|
||||||
import { createQuery, type CreateQueryResult } from '@tanstack/solid-query';
|
import { createQuery, type CreateQueryResult } from '@tanstack/solid-query';
|
||||||
import { nip05, nip19 } from 'nostr-tools';
|
import { nip05, nip19 } from 'nostr-tools';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { createSignal, onMount, Switch, Match, type Component } from 'solid-js';
|
import { createSignal, onMount, Switch, Match, type Component } from 'solid-js';
|
||||||
|
|
||||||
import { useNavigate } from '@solidjs/router';
|
import { useNavigate } from '@solidjs/router';
|
||||||
|
|
||||||
import usePersistStatus from '@/hooks/usePersistStatus';
|
import usePersistStatus from '@/hooks/usePersistStatus';
|
||||||
|
|
||||||
type SignerStatus = 'checking' | 'available' | 'unavailable';
|
type SignerStatus = 'checking' | 'available' | 'unavailable';
|
||||||
|
|||||||
@@ -8,26 +8,24 @@ import {
|
|||||||
Match,
|
Match,
|
||||||
type Component,
|
type Component,
|
||||||
} from 'solid-js';
|
} from 'solid-js';
|
||||||
|
|
||||||
import { useNavigate } from '@solidjs/router';
|
import { useNavigate } from '@solidjs/router';
|
||||||
import { createVirtualizer } from '@tanstack/solid-virtual';
|
import { createVirtualizer } from '@tanstack/solid-virtual';
|
||||||
import uniq from 'lodash/uniq';
|
import uniq from 'lodash/uniq';
|
||||||
|
|
||||||
import Column from '@/components/Column';
|
import Column from '@/components/Column';
|
||||||
import SideBar from '@/components/SideBar';
|
|
||||||
import Timeline from '@/components/Timeline';
|
|
||||||
import Notification from '@/components/Notification';
|
import Notification from '@/components/Notification';
|
||||||
import ProfileDisplay from '@/components/ProfileDisplay';
|
import ProfileDisplay from '@/components/ProfileDisplay';
|
||||||
|
import SideBar from '@/components/SideBar';
|
||||||
import usePool from '@/nostr/usePool';
|
import Timeline from '@/components/Timeline';
|
||||||
import useConfig from '@/nostr/useConfig';
|
|
||||||
import useSubscription from '@/nostr/useSubscription';
|
|
||||||
import useFollowings from '@/nostr/useFollowings';
|
|
||||||
import usePubkey from '@/nostr/usePubkey';
|
|
||||||
|
|
||||||
import { useMountShortcutKeys } from '@/hooks/useShortcutKeys';
|
|
||||||
import usePersistStatus from '@/hooks/usePersistStatus';
|
|
||||||
import useModalState from '@/hooks/useModalState';
|
import useModalState from '@/hooks/useModalState';
|
||||||
|
import usePersistStatus from '@/hooks/usePersistStatus';
|
||||||
|
import { useMountShortcutKeys } from '@/hooks/useShortcutKeys';
|
||||||
|
import useConfig from '@/nostr/useConfig';
|
||||||
|
import useFollowings from '@/nostr/useFollowings';
|
||||||
|
import usePool from '@/nostr/usePool';
|
||||||
|
import usePubkey from '@/nostr/usePubkey';
|
||||||
|
import useSubscription from '@/nostr/useSubscription';
|
||||||
import ensureNonNull from '@/utils/ensureNonNull';
|
import ensureNonNull from '@/utils/ensureNonNull';
|
||||||
import epoch from '@/utils/epoch';
|
import epoch from '@/utils/epoch';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export type TupleNonNull<T extends readonly any[]> = {
|
export type TupleNonNull<T extends readonly any[]> = {
|
||||||
[P in keyof T]: NonNullable<T[P]>;
|
[P in keyof T]: NonNullable<T[P]>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ensureNonNull =
|
const ensureNonNull =
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
|
||||||
|
|
||||||
<T extends readonly any[]>(tuple: T) =>
|
<T extends readonly any[]>(tuple: T) =>
|
||||||
<R>(f: (tupleNonNull: TupleNonNull<T>) => R): R | null => {
|
<R>(f: (tupleNonNull: TupleNonNull<T>) => R): R | null => {
|
||||||
if (tuple.some((e) => e == null)) {
|
if (tuple.some((e) => e == null)) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
import { describe, it } from 'vitest';
|
import { describe, it } from 'vitest';
|
||||||
|
|
||||||
import { fixUrl } from './imageUrl';
|
import { fixUrl } from './imageUrl';
|
||||||
|
|
||||||
describe('fixUrl', () => {
|
describe('fixUrl', () => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* eslint global-require: "off" */
|
/* eslint global-require: "off", @typescript-eslint/no-var-requires: "off" */
|
||||||
const colors = require('tailwindcss/colors');
|
const colors = require('tailwindcss/colors');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
import { defineConfig } from 'vitest/config';
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user