mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-09-19 12:00:32 +02:00
cleanup embedded article card
This commit is contained in:
@@ -21,7 +21,7 @@ I would recommend you use a browser extension like [Alby](https://getalby.com/)
|
||||
## Running with docker
|
||||
|
||||
```bash
|
||||
docker run --rm -p 8080:80 ghcr.io/hzrd149/nostrudel
|
||||
docker run --rm -p 8080:80 ghcr.io/hzrd149/nostrudel:master
|
||||
```
|
||||
|
||||
## Running locally
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { useRef } from "react";
|
||||
import { Card, CardProps, Flex, Image, LinkBox, LinkOverlay, Tag, Text } from "@chakra-ui/react";
|
||||
import { Box, Card, CardBody, CardProps, Flex, Image, LinkBox, LinkOverlay, Tag, Text } from "@chakra-ui/react";
|
||||
|
||||
import {
|
||||
getArticleImage,
|
||||
@@ -28,29 +28,39 @@ export default function EmbeddedArticle({ article, ...props }: Omit<CardProps, "
|
||||
useRegisterIntersectionEntity(ref, getEventUID(article));
|
||||
|
||||
return (
|
||||
<Card as={LinkBox} ref={ref} p="2" flexDirection="row" {...props}>
|
||||
<Flex gap="2" direction="column" flex={1}>
|
||||
<Flex gap="2" alignItems="center">
|
||||
<Card as={LinkBox} ref={ref} size="sm" {...props}>
|
||||
{image && (
|
||||
<Box
|
||||
backgroundImage={image}
|
||||
w="full"
|
||||
aspectRatio={3 / 1}
|
||||
hideFrom="md"
|
||||
backgroundRepeat="no-repeat"
|
||||
backgroundPosition="center"
|
||||
backgroundSize="cover"
|
||||
/>
|
||||
)}
|
||||
<CardBody>
|
||||
{image && (
|
||||
<Image src={image} alt={title} maxW="3in" maxH="2in" float="right" borderRadius="md" ml="2" hideBelow="md" />
|
||||
)}
|
||||
<Flex gap="2" alignItems="center" mb="2">
|
||||
<UserAvatarLink pubkey={article.pubkey} size="sm" />
|
||||
<LinkOverlay href={naddr ? buildAppSelectUrl(naddr, false) : undefined} isExternal fontWeight="bold">
|
||||
{title}
|
||||
</LinkOverlay>
|
||||
<Text>by:</Text>
|
||||
<UserLink pubkey={article.pubkey} />
|
||||
<Text>
|
||||
| <Timestamp timestamp={getArticlePublishDate(article) ?? article.created_at} />
|
||||
</Text>
|
||||
<UserLink pubkey={article.pubkey} fontWeight="bold" isTruncated />
|
||||
<Timestamp timestamp={getArticlePublishDate(article) ?? article.created_at} />
|
||||
</Flex>
|
||||
<Text flex={1}>{summary}</Text>
|
||||
<Flex gap="2" alignItems="center">
|
||||
{article.tags
|
||||
.filter((t) => t[0] === "t")
|
||||
.map(([_, hashtag]) => (
|
||||
<Tag>{hashtag}</Tag>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
{image && <Image src={image} alt={title} maxW="2in" maxH="2in" float="right" borderRadius="md" />}
|
||||
<LinkOverlay href={naddr ? buildAppSelectUrl(naddr, false) : undefined} isExternal fontWeight="bold">
|
||||
{title}
|
||||
</LinkOverlay>
|
||||
<Text mb="2">{summary}</Text>
|
||||
{article.tags
|
||||
.filter((t) => t[0] === "t")
|
||||
.map(([_, hashtag]) => (
|
||||
<Tag mr="2" mb="2">
|
||||
#{hashtag}
|
||||
</Tag>
|
||||
))}
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ import trustedUserStatsService, { NostrBandUserStats } from "../../services/trus
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import User01 from "../../components/icons/user-01";
|
||||
import GenericNoteTimeline from "../../components/timeline-page/generic-note-timeline";
|
||||
import Feather from "../../components/icons/feather";
|
||||
|
||||
function ProfileResult({ profile }: { profile: NostrEvent }) {
|
||||
const metadata = parseKind0Event(profile);
|
||||
@@ -120,6 +121,25 @@ function NoteSearchResults({ search }: { search: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
function ArticleSearchResults({ search }: { search: string }) {
|
||||
const searchRelays = useRelaySelectionRelays();
|
||||
|
||||
const timeline = useTimelineLoader(
|
||||
`${search}-article-search`,
|
||||
searchRelays,
|
||||
{ search: search || "", kinds: [Kind.Article] },
|
||||
{ enabled: !!search },
|
||||
);
|
||||
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
return (
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<GenericNoteTimeline timeline={timeline} />
|
||||
</IntersectionObserverProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export function SearchPage() {
|
||||
const navigate = useNavigate();
|
||||
const qrScannerModal = useDisclosure();
|
||||
@@ -168,7 +188,18 @@ export function SearchPage() {
|
||||
handleSearchText(searchInput);
|
||||
};
|
||||
|
||||
const SearchResults = type === "users" ? ProfileSearchResults : NoteSearchResults;
|
||||
let SearchResults = ProfileSearchResults;
|
||||
switch (type) {
|
||||
case "users":
|
||||
SearchResults = ProfileSearchResults;
|
||||
break;
|
||||
case "notes":
|
||||
SearchResults = NoteSearchResults;
|
||||
break;
|
||||
case "articles":
|
||||
SearchResults = ArticleSearchResults;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
@@ -203,11 +234,18 @@ export function SearchPage() {
|
||||
>
|
||||
Notes
|
||||
</Button>
|
||||
<Button
|
||||
leftIcon={<Feather />}
|
||||
colorScheme={type === "articles" ? "primary" : undefined}
|
||||
onClick={() => mergeSearchParams({ type: "articles" })}
|
||||
>
|
||||
Articles
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<RelaySelectionButton ml="auto" size="sm" />
|
||||
</Flex>
|
||||
|
||||
<Flex direction="column" gap="8">
|
||||
<Flex direction="column" gap="4">
|
||||
{search ? (
|
||||
<SearchResults search={search} />
|
||||
) : (
|
||||
|
Reference in New Issue
Block a user