alpha
Login
or
Join now
nandi.uk
/
semble
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
This repository has no description
Star
0
Fork
0
Atom
Configure Feed
Issues
Pull Requests
Commits
Tags
Feed URL
Select the types of activity you want to include in your feed.
Overview
Issues
Pulls
Pipelines
feat: url card, note card
author
Pouria Delfanazari
date
11 months ago
(Aug 21, 2025, 3:39 PM -0700)
commit
2d4edc51
2d4edc51712a148d51097c1069e7e3d623b3c12f
parent
55826147
5582614729821d50b8b817c26e8d141d602cd5b6
+127
-21
8 changed files
Expand all
Collapse all
Unified
Split
src
webapp
app
(authenticated)
collections
[collectionId]
page.tsx
library
page.tsx
components
FeedItem.tsx
UrlCardOld.tsx
features
cards
components
urlCard
UrlCard.tsx
collections
components
collectionCard
CollectionCard.tsx
notes
components
noteCard
NoteCard.tsx
lib
utils
link.ts
+5
-8
src/webapp/app/(authenticated)/collections/[collectionId]/page.tsx
View file
Reviewed
···
4
4
import { useRouter, useParams } from 'next/navigation';
5
5
import { getAccessToken } from '@/services/auth';
6
6
import { ApiClient } from '@/api-client/ApiClient';
7
7
-
import { UrlCard } from '@/components/UrlCard';
7
7
+
8
8
import type { GetCollectionPageResponse } from '@/api-client/types';
9
9
import {
10
10
Button,
···
17
17
Box,
18
18
SimpleGrid,
19
19
} from '@mantine/core';
20
20
+
import UrlCard from '@/features/cards/components/urlCard/UrlCard';
20
21
21
22
export default function CollectionPage() {
22
23
const [collection, setCollection] =
···
130
131
{collection.urlCards.map((card) => (
131
132
<UrlCard
132
133
key={card.id}
133
133
-
cardId={card.id}
134
134
+
id={card.id}
134
135
url={card.url}
135
135
-
title={card.cardContent.title}
136
136
-
description={card.cardContent.description}
137
137
-
author={card.cardContent.author}
138
138
-
imageUrl={card.cardContent.thumbnailUrl}
139
139
-
addedAt={card.createdAt}
140
140
-
note={card.note?.text}
136
136
+
cardContent={card.cardContent}
137
137
+
note={card.note}
141
138
/>
142
139
))}
143
140
</SimpleGrid>
+9
-9
src/webapp/app/(authenticated)/library/page.tsx
View file
Reviewed
···
4
4
import { useRouter } from 'next/navigation';
5
5
import { ApiClient } from '@/api-client/ApiClient';
6
6
import { getAccessToken } from '@/services/auth';
7
7
-
import { UrlCard } from '@/components/UrlCard';
7
7
+
import UrlCard from '@/features/cards/components/urlCard/UrlCard';
8
8
import type { GetMyUrlCardsResponse } from '@/api-client/types';
9
9
import {
10
10
Button,
···
62
62
{cardsLoading ? (
63
63
<Loader />
64
64
) : urlCards.length > 0 ? (
65
65
-
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing={'md'}>
65
65
+
<SimpleGrid
66
66
+
cols={{ base: 1, xs: 2, sm: 3, lg: 4, xl: 5 }}
67
67
+
spacing={'md'}
68
68
+
>
66
69
{urlCards.map((card) => (
67
70
<UrlCard
68
71
key={card.id}
69
69
-
cardId={card.id}
72
72
+
id={card.id}
70
73
url={card.url}
71
71
-
title={card.cardContent.title}
72
72
-
description={card.cardContent.description}
73
73
-
author={card.cardContent.author}
74
74
-
imageUrl={card.cardContent.thumbnailUrl}
75
75
-
addedAt={card.createdAt}
76
76
-
note={card.note?.text}
74
74
+
cardContent={card.cardContent}
75
75
+
note={card.note}
76
76
+
collections={card.collections}
77
77
/>
78
78
))}
79
79
</SimpleGrid>
+2
-2
src/webapp/components/FeedItem.tsx
View file
Reviewed
···
1
1
'use client';
2
2
3
3
import { useRouter } from 'next/navigation';
4
4
-
import { UrlCard } from './UrlCard';
4
4
+
import { UrlCard } from './UrlCardOld';
5
5
import type { FeedItem as FeedItemType } from '@/api-client/types';
6
6
-
import { Stack, Text, Group, Anchor, Box } from '@mantine/core';
6
6
+
import { Stack, Text, Anchor, Box } from '@mantine/core';
7
7
8
8
interface FeedItemProps {
9
9
item: FeedItemType;
src/webapp/components/UrlCard.tsx
src/webapp/components/UrlCardOld.tsx
View file
Reviewed
+87
src/webapp/features/cards/components/urlCard/UrlCard.tsx
View file
Reviewed
···
1
1
+
import { UrlCardView } from '@/api-client/types';
2
2
+
import { AddToCollectionModal } from '@/components/AddToCollectionModal';
3
3
+
import NoteCard from '@/features/notes/components/noteCard/NoteCard';
4
4
+
import { getDomain } from '@/lib/utils/link';
5
5
+
import {
6
6
+
Card,
7
7
+
Image,
8
8
+
Text,
9
9
+
Stack,
10
10
+
Group,
11
11
+
ActionIcon,
12
12
+
Anchor,
13
13
+
AspectRatio,
14
14
+
} from '@mantine/core';
15
15
+
import { useDisclosure } from '@mantine/hooks';
16
16
+
import Link from 'next/link';
17
17
+
import { BiPlus } from 'react-icons/bi';
18
18
+
19
19
+
interface Props {
20
20
+
size?: 'large' | 'compact' | 'small';
21
21
+
id: string;
22
22
+
url: string;
23
23
+
cardContent: UrlCardView['cardContent'];
24
24
+
note?: UrlCardView['note'];
25
25
+
collections?: UrlCardView['collections'];
26
26
+
libraries?: UrlCardView['libraries'];
27
27
+
}
28
28
+
29
29
+
export default function UrlCard(props: Props) {
30
30
+
const domain = getDomain(props.url);
31
31
+
const [modalOpened, { open, close }] = useDisclosure(false);
32
32
+
// TODO: add more sizes
33
33
+
34
34
+
return (
35
35
+
<Stack component="article" gap={5} justify="stretch">
36
36
+
<Card withBorder radius={'lg'} p={'sm'} flex={1}>
37
37
+
<Stack justify="space-between" gap={'sm'} flex={1}>
38
38
+
<Group justify="space-between" align="start" wrap="nowrap" gap={'lg'}>
39
39
+
<Stack gap={0}>
40
40
+
<Anchor
41
41
+
component={Link}
42
42
+
href={props.url}
43
43
+
target="_blank"
44
44
+
c={'gray'}
45
45
+
lineClamp={1}
46
46
+
>
47
47
+
{domain}
48
48
+
</Anchor>
49
49
+
{props.cardContent.title && (
50
50
+
<Text fw={500} lineClamp={1}>
51
51
+
{props.cardContent.title}
52
52
+
</Text>
53
53
+
)}
54
54
+
</Stack>
55
55
+
{props.cardContent.thumbnailUrl && (
56
56
+
<AspectRatio ratio={1 / 1}>
57
57
+
<Image
58
58
+
src={props.cardContent.thumbnailUrl}
59
59
+
alt={`${props.url} social preview image`}
60
60
+
radius={'md'}
61
61
+
w={75}
62
62
+
h={75}
63
63
+
/>
64
64
+
</AspectRatio>
65
65
+
)}
66
66
+
</Group>
67
67
+
<Group justify="space-between">
68
68
+
<ActionIcon
69
69
+
variant="subtle"
70
70
+
color={'gray'}
71
71
+
radius={'xl'}
72
72
+
onClick={open}
73
73
+
>
74
74
+
<BiPlus size={22} />
75
75
+
</ActionIcon>
76
76
+
</Group>
77
77
+
</Stack>
78
78
+
</Card>
79
79
+
{props.note && <NoteCard note={props.note.text} />}
80
80
+
<AddToCollectionModal
81
81
+
cardId={props.id}
82
82
+
isOpen={modalOpened}
83
83
+
onClose={close}
84
84
+
/>
85
85
+
</Stack>
86
86
+
);
87
87
+
}
+4
-2
src/webapp/features/collections/components/collectionCard/CollectionCard.tsx
View file
Reviewed
···
38
38
>
39
39
<Stack justify="space-between" h={'100%'}>
40
40
<Stack gap={0}>
41
41
-
<Text fw={600} fz={'lg'} lineClamp={1}>
41
41
+
<Text fw={500} lineClamp={1}>
42
42
{collection.name}
43
43
</Text>
44
44
{collection.description && (
···
49
49
</Stack>
50
50
<Group justify="space-between">
51
51
<Text c={'gray'}>
52
52
-
{collection.cardCount} · {relativeUpdateDate}
52
52
+
{collection.cardCount}{' '}
53
53
+
{collection.cardCount === 1 ? 'card' : 'cards'} ·{' '}
54
54
+
{relativeUpdateDate}
53
55
</Text>
54
56
<Anchor
55
57
component={Link}
+17
src/webapp/features/notes/components/noteCard/NoteCard.tsx
View file
Reviewed
···
1
1
+
import { Card, Spoiler, Text } from '@mantine/core';
2
2
+
3
3
+
interface Props {
4
4
+
note: string;
5
5
+
}
6
6
+
7
7
+
export default function NoteCard(props: Props) {
8
8
+
return (
9
9
+
<Card bg={'#E5E8E7'} p={'sm'}>
10
10
+
<Spoiler showLabel={'Read more'} hideLabel={'See less'} maxHeight={45}>
11
11
+
<Text fz={'sm'} c={'#74867F'}>
12
12
+
{props.note}
13
13
+
</Text>
14
14
+
</Spoiler>
15
15
+
</Card>
16
16
+
);
17
17
+
}
+3
src/webapp/lib/utils/link.ts
View file
Reviewed
···
1
1
+
export const getDomain = (url: string) => {
2
2
+
return new URL(url).hostname;
3
3
+
};