mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-09-27 20:17:05 +02:00
some work
This commit is contained in:
@@ -48,6 +48,9 @@ export default function NavItems({ isInDrawer = false }: { isInDrawer?: boolean
|
|||||||
<Button onClick={() => navigate("/streams")} leftIcon={<LiveStreamIcon />} justifyContent="flex-start">
|
<Button onClick={() => navigate("/streams")} leftIcon={<LiveStreamIcon />} justifyContent="flex-start">
|
||||||
Streams
|
Streams
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button onClick={() => navigate("/files")} leftIcon={<FileIcon />} justifyContent="flex-start">
|
||||||
|
Files
|
||||||
|
</Button>
|
||||||
<Button onClick={() => navigate("/lists")} leftIcon={<ListIcon />} justifyContent="flex-start">
|
<Button onClick={() => navigate("/lists")} leftIcon={<ListIcon />} justifyContent="flex-start">
|
||||||
Lists
|
Lists
|
||||||
</Button>
|
</Button>
|
||||||
@@ -57,9 +60,6 @@ export default function NavItems({ isInDrawer = false }: { isInDrawer?: boolean
|
|||||||
<Button onClick={() => navigate("/emojis")} leftIcon={<EmojiIcon />} justifyContent="flex-start">
|
<Button onClick={() => navigate("/emojis")} leftIcon={<EmojiIcon />} justifyContent="flex-start">
|
||||||
Emojis
|
Emojis
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => navigate("/files")} leftIcon={<FileIcon />} justifyContent="flex-start">
|
|
||||||
Files
|
|
||||||
</Button>
|
|
||||||
<Button onClick={() => navigate("/map")} leftIcon={<MapIcon />} justifyContent="flex-start">
|
<Button onClick={() => navigate("/map")} leftIcon={<MapIcon />} justifyContent="flex-start">
|
||||||
Map
|
Map
|
||||||
</Button>
|
</Button>
|
||||||
|
@@ -12,8 +12,14 @@ export type ParsedImageFile = {
|
|||||||
blurhash?: string;
|
blurhash?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function parseImageFile(event: NostrEvent): ParsedImageFile {
|
export function getFileUrl(event: NostrEvent) {
|
||||||
const url = event.tags.find((t) => t[0] === "url" && t[1])?.[1];
|
const url = event.tags.find((t) => t[0] === "url" && t[1])?.[1];
|
||||||
|
if (!url) throw new Error("Missing url");
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseImageFile(event: NostrEvent): ParsedImageFile {
|
||||||
|
const url = getFileUrl(event);
|
||||||
const mimeType = event.tags.find((t) => t[0] === "m" && t[1])?.[1];
|
const mimeType = event.tags.find((t) => t[0] === "m" && t[1])?.[1];
|
||||||
const magnet = event.tags.find((t) => t[0] === "magnet" && t[1])?.[1];
|
const magnet = event.tags.find((t) => t[0] === "magnet" && t[1])?.[1];
|
||||||
const infoHash = event.tags.find((t) => t[0] === "i" && t[1])?.[1];
|
const infoHash = event.tags.find((t) => t[0] === "i" && t[1])?.[1];
|
||||||
@@ -24,7 +30,6 @@ export function parseImageFile(event: NostrEvent): ParsedImageFile {
|
|||||||
const dimensions = event.tags.find((t) => t[0] === "dim" && t[1])?.[1];
|
const dimensions = event.tags.find((t) => t[0] === "dim" && t[1])?.[1];
|
||||||
const [width, height] = dimensions?.split("x").map((v) => parseInt(v)) ?? [];
|
const [width, height] = dimensions?.split("x").map((v) => parseInt(v)) ?? [];
|
||||||
|
|
||||||
if (!url) throw new Error("missing url");
|
|
||||||
if (!mimeType) throw new Error("missing MIME Type");
|
if (!mimeType) throw new Error("missing MIME Type");
|
||||||
if (width !== undefined && height !== undefined) {
|
if (width !== undefined && height !== undefined) {
|
||||||
if (!Number.isFinite(width) || !Number.isFinite(height)) throw new Error("bad dimensions");
|
if (!Number.isFinite(width) || !Number.isFinite(height)) throw new Error("bad dimensions");
|
||||||
|
@@ -20,12 +20,19 @@ import useTimelineLoader from "../../hooks/use-timeline-loader";
|
|||||||
import { useReadRelayUrls } from "../../hooks/use-client-relays";
|
import { useReadRelayUrls } from "../../hooks/use-client-relays";
|
||||||
import useSubject from "../../hooks/use-subject";
|
import useSubject from "../../hooks/use-subject";
|
||||||
import { NostrEvent } from "../../types/nostr-event";
|
import { NostrEvent } from "../../types/nostr-event";
|
||||||
import { parseImageFile } from "../../helpers/nostr/files";
|
import { getFileUrl, parseImageFile } from "../../helpers/nostr/files";
|
||||||
import BlurhashImage from "../../components/blurhash-image";
|
import BlurhashImage from "../../components/blurhash-image";
|
||||||
import { ErrorBoundary } from "../../components/error-boundary";
|
import { ErrorBoundary } from "../../components/error-boundary";
|
||||||
import useAppSettings from "../../hooks/use-app-settings";
|
import useAppSettings from "../../hooks/use-app-settings";
|
||||||
import { useTrusted } from "../../providers/trust";
|
import { TrustProvider, useTrusted } from "../../providers/trust";
|
||||||
import BlurredImage from "../../components/blured-image";
|
import BlurredImage from "../../components/blured-image";
|
||||||
|
import PeopleListProvider, { usePeopleListContext } from "../../providers/people-list-provider";
|
||||||
|
import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/relay-selection-provider";
|
||||||
|
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
|
||||||
|
import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
|
||||||
|
import { UserAvatar } from "../../components/user-avatar";
|
||||||
|
import { UserAvatarLink } from "../../components/user-avatar-link";
|
||||||
|
import { UserLink } from "../../components/user-link";
|
||||||
|
|
||||||
const FILE_KIND = 1063;
|
const FILE_KIND = 1063;
|
||||||
const VIDEO_TYPES = ["video/mp4", "video/webm"];
|
const VIDEO_TYPES = ["video/mp4", "video/webm"];
|
||||||
@@ -40,23 +47,45 @@ function ImageFile({ event }: { event: NostrEvent }) {
|
|||||||
|
|
||||||
const shouldBlur = settings.blurImages && !trust;
|
const shouldBlur = settings.blurImages && !trust;
|
||||||
|
|
||||||
const showImage = useDisclosure();
|
// const showImage = useDisclosure();
|
||||||
if (shouldBlur && parsed.blurhash && parsed.width && parsed.height && !showImage.isOpen) {
|
// if (shouldBlur && parsed.blurhash && parsed.width && parsed.height && !showImage.isOpen) {
|
||||||
const aspect = parsed.width / parsed.height;
|
// const aspect = parsed.width / parsed.height;
|
||||||
|
// return (
|
||||||
|
// <BlurhashImage
|
||||||
|
// blurhash={parsed.blurhash}
|
||||||
|
// width={64 * aspect}
|
||||||
|
// height={64}
|
||||||
|
// onClick={showImage.onOpen}
|
||||||
|
// cursor="pointer"
|
||||||
|
// w="full"
|
||||||
|
// />
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
const ImageComponent = shouldBlur ? BlurredImage : Image;
|
||||||
return (
|
return (
|
||||||
<BlurhashImage
|
<Flex direction="column" gap="2">
|
||||||
blurhash={parsed.blurhash}
|
<Flex gap="2" alignItems="center">
|
||||||
width={64 * aspect}
|
<UserAvatarLink pubkey={event.pubkey} size="sm" />
|
||||||
height={64}
|
<UserLink pubkey={event.pubkey} fontWeight="bold" />
|
||||||
onClick={showImage.onOpen}
|
</Flex>
|
||||||
cursor="pointer"
|
<ImageComponent src={parsed.url} w="full" />
|
||||||
w="full"
|
</Flex>
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImageComponent = shouldBlur ? BlurredImage : Image;
|
function VideoFile({ event }: { event: NostrEvent }) {
|
||||||
return <ImageComponent src={parsed.url} w="full" />;
|
const url = getFileUrl(event);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
<Flex gap="2" alignItems="center">
|
||||||
|
<UserAvatarLink pubkey={event.pubkey} size="sm" />
|
||||||
|
<UserLink pubkey={event.pubkey} fontWeight="bold" />
|
||||||
|
</Flex>
|
||||||
|
<video src={url} controls />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function FileType({ event }: { event: NostrEvent }) {
|
function FileType({ event }: { event: NostrEvent }) {
|
||||||
@@ -65,12 +94,22 @@ function FileType({ event }: { event: NostrEvent }) {
|
|||||||
if (!mimeType) throw new Error("missing MIME type");
|
if (!mimeType) throw new Error("missing MIME type");
|
||||||
|
|
||||||
if (IMAGE_TYPES.includes(mimeType)) {
|
if (IMAGE_TYPES.includes(mimeType)) {
|
||||||
return <ImageFile event={event} />;
|
return (
|
||||||
|
<TrustProvider trust>
|
||||||
|
<ImageFile event={event} />
|
||||||
|
</TrustProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (VIDEO_TYPES.includes(mimeType)) {
|
||||||
|
return <VideoFile event={event} />;
|
||||||
}
|
}
|
||||||
return <Text>Unknown mine type {mimeType}</Text>;
|
return <Text>Unknown mine type {mimeType}</Text>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function FilesView() {
|
function FilesPage() {
|
||||||
|
const { listId, filter } = usePeopleListContext();
|
||||||
|
const { relays } = useRelaySelectionContext();
|
||||||
|
|
||||||
const [selectedTypes, setSelectedTypes] = useState<string[]>(IMAGE_TYPES);
|
const [selectedTypes, setSelectedTypes] = useState<string[]>(IMAGE_TYPES);
|
||||||
const toggleType = useCallback(
|
const toggleType = useCallback(
|
||||||
(type: string) => {
|
(type: string) => {
|
||||||
@@ -80,22 +119,22 @@ export default function FilesView() {
|
|||||||
} else return arr.concat(type);
|
} else return arr.concat(type);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[setSelectedTypes]
|
[setSelectedTypes],
|
||||||
);
|
);
|
||||||
|
|
||||||
const relays = useReadRelayUrls();
|
|
||||||
const timeline = useTimelineLoader(
|
const timeline = useTimelineLoader(
|
||||||
"files",
|
`${listId}-files`,
|
||||||
relays,
|
relays,
|
||||||
{ kinds: [FILE_KIND], "#m": selectedTypes },
|
{ kinds: [FILE_KIND], "#m": selectedTypes, ...filter },
|
||||||
{ enabled: selectedTypes.length > 0 }
|
{ enabled: selectedTypes.length > 0 && !!filter },
|
||||||
);
|
);
|
||||||
|
|
||||||
const events = useSubject(timeline.timeline);
|
const events = useSubject(timeline.timeline);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" gap="2" p="2">
|
<Flex direction="column" gap="2" p="2">
|
||||||
<Flex>
|
<Flex gap="2">
|
||||||
|
<PeopleListSelection />
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
<Button>{selectedTypes.length} Selected types</Button>
|
<Button>{selectedTypes.length} Selected types</Button>
|
||||||
@@ -145,6 +184,7 @@ export default function FilesView() {
|
|||||||
</PopoverBody>
|
</PopoverBody>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
<RelaySelectionButton ml="auto" />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<SimpleGrid minChildWidth="20rem" spacing="2">
|
<SimpleGrid minChildWidth="20rem" spacing="2">
|
||||||
@@ -158,3 +198,13 @@ export default function FilesView() {
|
|||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function FilesView() {
|
||||||
|
return (
|
||||||
|
<PeopleListProvider>
|
||||||
|
<RelaySelectionProvider>
|
||||||
|
<FilesPage />
|
||||||
|
</RelaySelectionProvider>
|
||||||
|
</PeopleListProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user