+331
-323
Diff
round #0
+137
-141
apps/web/src/components/ContextMenu/ContextMenu.tsx
+137
-141
apps/web/src/components/ContextMenu/ContextMenu.tsx
···
4
4
import { StatefulPopover } from "baseui/popover";
5
5
6
6
export type ContextMenuProps = {
7
-
file: {
8
-
id: string;
9
-
name: string;
10
-
type: string;
11
-
};
7
+
file: {
8
+
id: string;
9
+
name: string;
10
+
type: string;
11
+
};
12
12
};
13
13
14
14
function ContextMenu(props: ContextMenuProps) {
15
-
const { file } = props;
16
-
return (
17
-
<>
18
-
<StatefulPopover
19
-
autoFocus={false}
20
-
content={({ close }) => (
21
-
<div className="border-[var(--color-border)] w-[240px] border-[1px] bg-[var(--color-background)] rounded-[6px]">
22
-
<div
23
-
className="h-[54px] flex flex-row items-center pl-[5px] pr-[5px]"
24
-
style={{
25
-
borderBottom: "1px solid var(--color-border)",
26
-
}}
27
-
>
28
-
<div className="h-[43px] flex items-center justify-center ml-[10px] mr-[10px] text-[var(--color-text)]">
29
-
{file.type == "folder" && (
30
-
<div>
31
-
<Folder2 size={20} />
32
-
</div>
33
-
)}
34
-
{file.type !== "folder" && (
35
-
<div>
36
-
<MusicNoteBeamed size={20} />
37
-
</div>
38
-
)}
39
-
</div>
40
-
<div className="text-[var(--color-text)] whitespace-nowrap text-ellipsis overflow-hidden">
41
-
{file.name}
42
-
</div>
43
-
</div>
44
-
<NestedMenus>
45
-
<StatefulMenu
46
-
items={[
47
-
{
48
-
id: "0",
49
-
label: "Play",
50
-
},
51
-
{
52
-
id: "1",
53
-
label: "Play Next",
54
-
},
55
-
{
56
-
id: "2",
57
-
label: "Add to Playlist",
58
-
},
59
-
{
60
-
id: "3",
61
-
label: "Play Last",
62
-
},
63
-
{
64
-
id: "4",
65
-
label: "Add Shuffled",
66
-
},
67
-
]}
68
-
onItemSelect={({ item }) => {
69
-
console.log(`Selected item: ${item.label}`);
70
-
close();
71
-
}}
72
-
overrides={{
73
-
List: {
74
-
style: {
75
-
boxShadow: "none",
76
-
outline: "none !important",
77
-
backgroundColor: "var(--color-background)",
78
-
},
79
-
},
80
-
ListItem: {
81
-
style: {
82
-
backgroundColor: "var(--color-background)",
83
-
color: "var(--color-text)",
84
-
":hover": {
85
-
backgroundColor: "var(--color-menu-hover)",
86
-
},
87
-
},
88
-
},
89
-
Option: {
90
-
props: {
91
-
getChildMenu: (item: { label: string }) => {
92
-
if (item.label === "Add to Playlist") {
93
-
return (
94
-
<div className="border-[var(--color-border)] w-[205px] border-[1px] bg-[var(--color-background)] rounded-[6px]">
95
-
<StatefulMenu
96
-
items={{
97
-
__ungrouped: [
98
-
{
99
-
label: "Create new playlist",
100
-
},
101
-
],
102
-
}}
103
-
overrides={{
104
-
List: {
105
-
style: {
106
-
boxShadow: "none",
107
-
outline: "none !important",
108
-
backgroundColor:
109
-
"var(--color-background)",
110
-
},
111
-
},
112
-
ListItem: {
113
-
style: {
114
-
backgroundColor:
115
-
"var(--color-background)",
116
-
color: "var(--color-text)",
117
-
":hover": {
118
-
backgroundColor:
119
-
"var(--color-menu-hover)",
120
-
},
121
-
},
122
-
},
123
-
}}
124
-
/>
125
-
</div>
126
-
);
127
-
}
128
-
return null;
129
-
},
130
-
},
131
-
},
132
-
}}
133
-
/>
134
-
</NestedMenus>
135
-
</div>
136
-
)}
137
-
overrides={{
138
-
Inner: {
139
-
style: {
140
-
backgroundColor: "var(--color-background)",
141
-
},
142
-
},
143
-
}}
144
-
>
145
-
<button className="text-[var(--color-text-muted)] cursor-pointer bg-transparent border-none hover:bg-transparent">
146
-
<EllipsisHorizontal size={24} />
147
-
</button>
148
-
</StatefulPopover>
149
-
</>
150
-
);
15
+
const { file } = props;
16
+
return (
17
+
<StatefulPopover
18
+
autoFocus={false}
19
+
content={({ close }) => (
20
+
<div className="border-[var(--color-border)] w-[240px] border-[1px] bg-[var(--color-background)] rounded-[6px]">
21
+
<div
22
+
className="h-[54px] flex flex-row items-center pl-[5px] pr-[5px]"
23
+
style={{
24
+
borderBottom: "1px solid var(--color-border)",
25
+
}}
26
+
>
27
+
<div className="h-[43px] flex items-center justify-center ml-[10px] mr-[10px] text-[var(--color-text)]">
28
+
{file.type == "folder" && (
29
+
<div>
30
+
<Folder2 size={20} />
31
+
</div>
32
+
)}
33
+
{file.type !== "folder" && (
34
+
<div>
35
+
<MusicNoteBeamed size={20} />
36
+
</div>
37
+
)}
38
+
</div>
39
+
<div className="text-[var(--color-text)] whitespace-nowrap text-ellipsis overflow-hidden">
40
+
{file.name}
41
+
</div>
42
+
</div>
43
+
<NestedMenus>
44
+
<StatefulMenu
45
+
items={[
46
+
{
47
+
id: "0",
48
+
label: "Play",
49
+
},
50
+
{
51
+
id: "1",
52
+
label: "Play Next",
53
+
},
54
+
{
55
+
id: "2",
56
+
label: "Add to Playlist",
57
+
},
58
+
{
59
+
id: "3",
60
+
label: "Play Last",
61
+
},
62
+
{
63
+
id: "4",
64
+
label: "Add Shuffled",
65
+
},
66
+
]}
67
+
onItemSelect={({ item }) => {
68
+
console.log(`Selected item: ${item.label}`);
69
+
close();
70
+
}}
71
+
overrides={{
72
+
List: {
73
+
style: {
74
+
boxShadow: "none",
75
+
outline: "none !important",
76
+
backgroundColor: "var(--color-background)",
77
+
},
78
+
},
79
+
ListItem: {
80
+
style: {
81
+
backgroundColor: "var(--color-background)",
82
+
color: "var(--color-text)",
83
+
":hover": {
84
+
backgroundColor: "var(--color-menu-hover)",
85
+
},
86
+
},
87
+
},
88
+
Option: {
89
+
props: {
90
+
getChildMenu: (item: { label: string }) => {
91
+
if (item.label === "Add to Playlist") {
92
+
return (
93
+
<div className="border-[var(--color-border)] w-[205px] border-[1px] bg-[var(--color-background)] rounded-[6px]">
94
+
<StatefulMenu
95
+
items={{
96
+
__ungrouped: [
97
+
{
98
+
label: "Create new playlist",
99
+
},
100
+
],
101
+
}}
102
+
overrides={{
103
+
List: {
104
+
style: {
105
+
boxShadow: "none",
106
+
outline: "none !important",
107
+
backgroundColor: "var(--color-background)",
108
+
},
109
+
},
110
+
ListItem: {
111
+
style: {
112
+
backgroundColor: "var(--color-background)",
113
+
color: "var(--color-text)",
114
+
":hover": {
115
+
backgroundColor:
116
+
"var(--color-menu-hover)",
117
+
},
118
+
},
119
+
},
120
+
}}
121
+
/>
122
+
</div>
123
+
);
124
+
}
125
+
return null;
126
+
},
127
+
},
128
+
},
129
+
}}
130
+
/>
131
+
</NestedMenus>
132
+
</div>
133
+
)}
134
+
overrides={{
135
+
Inner: {
136
+
style: {
137
+
backgroundColor: "var(--color-background)",
138
+
},
139
+
},
140
+
}}
141
+
>
142
+
<button className="text-[var(--color-text-muted)] cursor-pointer bg-transparent border-none hover:bg-transparent">
143
+
<EllipsisHorizontal size={24} />
144
+
</button>
145
+
</StatefulPopover>
146
+
);
151
147
}
152
148
153
149
export default ContextMenu;
+94
-96
apps/web/src/components/Handle/Handle.tsx
+94
-96
apps/web/src/components/Handle/Handle.tsx
···
8
8
import { profilesAtom } from "../../atoms/profiles";
9
9
import { statsAtom } from "../../atoms/stats";
10
10
import {
11
-
useProfileByDidQuery,
12
-
useProfileStatsByDidQuery,
11
+
useProfileByDidQuery,
12
+
useProfileStatsByDidQuery,
13
13
} from "../../hooks/useProfile";
14
14
import Stats from "../Stats";
15
15
import NowPlaying from "./NowPlaying";
16
16
17
17
export type HandleProps = {
18
-
link: string;
19
-
did: string;
18
+
link: string;
19
+
did: string;
20
20
};
21
21
22
22
function Handle(props: HandleProps) {
23
-
const { link, did } = props;
24
-
const [profiles, setProfiles] = useAtom(profilesAtom);
25
-
const profile = useProfileByDidQuery(did);
26
-
const profileStats = useProfileStatsByDidQuery(did);
27
-
const [stats, setStats] = useAtom(statsAtom);
23
+
const { link, did } = props;
24
+
const [profiles, setProfiles] = useAtom(profilesAtom);
25
+
const profile = useProfileByDidQuery(did);
26
+
const profileStats = useProfileStatsByDidQuery(did);
27
+
const [stats, setStats] = useAtom(statsAtom);
28
28
29
-
useEffect(() => {
30
-
if (profile.isLoading || profile.isError) {
31
-
return;
32
-
}
29
+
useEffect(() => {
30
+
if (profile.isLoading || profile.isError) {
31
+
return;
32
+
}
33
33
34
-
if (!profile.data || !did) {
35
-
return;
36
-
}
34
+
if (!profile.data || !did) {
35
+
return;
36
+
}
37
37
38
-
setProfiles((profiles) => ({
39
-
...profiles,
40
-
[did]: {
41
-
avatar: profile.data.avatar,
42
-
displayName: profile.data.displayName,
43
-
handle: profile.data.handle,
44
-
spotifyConnected: profile.data.spotifyConnected,
45
-
createdAt: profile.data.createdAt,
46
-
did,
47
-
},
48
-
}));
38
+
setProfiles((profiles) => ({
39
+
...profiles,
40
+
[did]: {
41
+
avatar: profile.data.avatar,
42
+
displayName: profile.data.displayName,
43
+
handle: profile.data.handle,
44
+
spotifyConnected: profile.data.spotifyConnected,
45
+
createdAt: profile.data.createdAt,
46
+
did,
47
+
},
48
+
}));
49
49
50
-
// eslint-disable-next-line react-hooks/exhaustive-deps
51
-
}, [profile.data, profile.isLoading, profile.isError, did]);
50
+
// eslint-disable-next-line react-hooks/exhaustive-deps
51
+
}, [profile.data, profile.isLoading, profile.isError, did]);
52
52
53
-
useEffect(() => {
54
-
if (profileStats.isLoading || profileStats.isError) {
55
-
return;
56
-
}
53
+
useEffect(() => {
54
+
if (profileStats.isLoading || profileStats.isError) {
55
+
return;
56
+
}
57
57
58
-
if (!profileStats.data || !did) {
59
-
return;
60
-
}
58
+
if (!profileStats.data || !did) {
59
+
return;
60
+
}
61
61
62
-
setStats((prev) => ({
63
-
...prev,
64
-
[did]: {
65
-
scrobbles: profileStats.data.scrobbles,
66
-
artists: profileStats.data.artists,
67
-
lovedTracks: profileStats.data.lovedTracks,
68
-
albums: profileStats.data.albums,
69
-
tracks: profileStats.data.tracks,
70
-
},
71
-
}));
72
-
// eslint-disable-next-line react-hooks/exhaustive-deps
73
-
}, [profileStats.data, profileStats.isLoading, profileStats.isError, did]);
62
+
setStats((prev) => ({
63
+
...prev,
64
+
[did]: {
65
+
scrobbles: profileStats.data.scrobbles,
66
+
artists: profileStats.data.artists,
67
+
lovedTracks: profileStats.data.lovedTracks,
68
+
albums: profileStats.data.albums,
69
+
tracks: profileStats.data.tracks,
70
+
},
71
+
}));
72
+
// eslint-disable-next-line react-hooks/exhaustive-deps
73
+
}, [profileStats.data, profileStats.isLoading, profileStats.isError, did]);
74
74
75
-
return (
76
-
<>
77
-
<StatefulPopover
78
-
content={() => (
79
-
<Block className="!bg-[var(--color-background)] !text-[var(--color-text)] p-[15px] w-[380px] rounded-[6px] border-[1px] border-[var(--color-border)]">
80
-
<div className="flex flex-row items-center">
81
-
<Link to={link} className="no-underline">
82
-
<Avatar
83
-
src={profiles[did]?.avatar}
84
-
name={profiles[did]?.displayName}
85
-
size={"60px"}
86
-
/>
87
-
</Link>
88
-
<div className="ml-[16px]">
89
-
<Link to={link} className="no-underline">
90
-
<LabelMedium
91
-
marginTop={"10px"}
92
-
className="!text-[var(--color-text)]"
93
-
>
94
-
{profiles[did]?.displayName}
95
-
</LabelMedium>
96
-
</Link>
97
-
<a
98
-
href={`https://bsky.app/profile/${profiles[did]?.handle}`}
99
-
className="no-underline text-[var(--color-primary)]"
100
-
>
101
-
<LabelSmall className="!text-[var(--color-primary)] mt-[3px] mb-[25px]">
102
-
@{did}
103
-
</LabelSmall>
104
-
</a>
105
-
</div>
106
-
</div>
75
+
return (
76
+
<StatefulPopover
77
+
content={() => (
78
+
<Block className="!bg-[var(--color-background)] !text-[var(--color-text)] p-[15px] w-[380px] rounded-[6px] border-[1px] border-[var(--color-border)]">
79
+
<div className="flex flex-row items-center">
80
+
<Link to={link} className="no-underline">
81
+
<Avatar
82
+
src={profiles[did]?.avatar}
83
+
name={profiles[did]?.displayName}
84
+
size={"60px"}
85
+
/>
86
+
</Link>
87
+
<div className="ml-[16px]">
88
+
<Link to={link} className="no-underline">
89
+
<LabelMedium
90
+
marginTop={"10px"}
91
+
className="!text-[var(--color-text)]"
92
+
>
93
+
{profiles[did]?.displayName}
94
+
</LabelMedium>
95
+
</Link>
96
+
<a
97
+
href={`https://bsky.app/profile/${profiles[did]?.handle}`}
98
+
className="no-underline text-[var(--color-primary)]"
99
+
>
100
+
<LabelSmall className="!text-[var(--color-primary)] mt-[3px] mb-[25px]">
101
+
@{did}
102
+
</LabelSmall>
103
+
</a>
104
+
</div>
105
+
</div>
107
106
108
-
{stats[did] && <Stats stats={stats[did]} mb={1} />}
107
+
{stats[did] && <Stats stats={stats[did]} mb={1} />}
109
108
110
-
<NowPlaying did={did} />
111
-
</Block>
112
-
)}
113
-
triggerType={TRIGGER_TYPE.hover}
114
-
autoFocus={false}
115
-
focusLock={false}
116
-
>
117
-
<Link to={link} className="no-underline">
118
-
<LabelMedium className="!text-[var(--color-primary)] !overflow-hidden !text-ellipsis !max-w-[250px]">
119
-
@{did}
120
-
</LabelMedium>
121
-
</Link>
122
-
</StatefulPopover>
123
-
</>
124
-
);
109
+
<NowPlaying did={did} />
110
+
</Block>
111
+
)}
112
+
triggerType={TRIGGER_TYPE.hover}
113
+
autoFocus={false}
114
+
focusLock={false}
115
+
>
116
+
<Link to={link} className="no-underline">
117
+
<LabelMedium className="!text-[var(--color-primary)] !overflow-hidden !text-ellipsis !max-w-[220px] !text-[14px]">
118
+
@{did}
119
+
</LabelMedium>
120
+
</Link>
121
+
</StatefulPopover>
122
+
);
125
123
}
126
124
127
125
export default Handle;
+100
-86
apps/web/src/pages/home/feed/Feed.tsx
+100
-86
apps/web/src/pages/home/feed/Feed.tsx
···
1
1
import styled from "@emotion/styled";
2
2
import { Link } from "@tanstack/react-router";
3
+
import { Avatar } from "baseui/avatar";
3
4
import type { BlockProps } from "baseui/block";
4
5
import { FlexGrid, FlexGridItem } from "baseui/flex-grid";
5
6
import { StatefulTooltip } from "baseui/tooltip";
6
-
import { HeadingMedium, LabelMedium } from "baseui/typography";
7
+
import { HeadingMedium, LabelSmall } from "baseui/typography";
7
8
import dayjs from "dayjs";
8
9
import relativeTime from "dayjs/plugin/relativeTime";
9
10
import ContentLoader from "react-content-loader";
···
14
15
dayjs.extend(relativeTime);
15
16
16
17
const itemProps: BlockProps = {
17
-
display: "flex",
18
-
alignItems: "flex-start",
19
-
flexDirection: "column",
18
+
display: "flex",
19
+
alignItems: "flex-start",
20
+
flexDirection: "column",
20
21
};
21
22
22
23
const Container = styled.div`
···
27
28
`;
28
29
29
30
function Feed() {
30
-
const { data, isLoading } = useFeedQuery();
31
-
return (
32
-
<Container>
33
-
<HeadingMedium
34
-
marginTop={"0px"}
35
-
marginBottom={"20px"}
36
-
className="!text-[var(--color-text)]"
37
-
>
38
-
Recently played
39
-
</HeadingMedium>
31
+
const { data, isLoading } = useFeedQuery();
32
+
console.log(data);
33
+
return (
34
+
<Container>
35
+
<HeadingMedium
36
+
marginTop={"0px"}
37
+
marginBottom={"25px"}
38
+
className="!text-[var(--color-text)]"
39
+
>
40
+
Recently played
41
+
</HeadingMedium>
40
42
41
-
{isLoading && (
42
-
<ContentLoader
43
-
width={800}
44
-
height={575}
45
-
viewBox="0 0 800 575"
46
-
backgroundColor="var(--color-skeleton-background)"
47
-
foregroundColor="var(--color-skeleton-foreground)"
48
-
>
49
-
<rect x="12" y="9" rx="2" ry="2" width="140" height="10" />
50
-
<rect x="14" y="30" rx="2" ry="2" width="667" height="11" />
51
-
<rect x="12" y="58" rx="2" ry="2" width="211" height="211" />
52
-
<rect x="240" y="57" rx="2" ry="2" width="211" height="211" />
53
-
<rect x="467" y="56" rx="2" ry="2" width="211" height="211" />
54
-
<rect x="12" y="283" rx="2" ry="2" width="211" height="211" />
55
-
<rect x="240" y="281" rx="2" ry="2" width="211" height="211" />
56
-
<rect x="468" y="279" rx="2" ry="2" width="211" height="211" />
57
-
<circle cx="286" cy="536" r="12" />
58
-
<circle cx="319" cy="535" r="12" />
59
-
<circle cx="353" cy="535" r="12" />
60
-
<rect x="378" y="524" rx="0" ry="0" width="52" height="24" />
61
-
<rect x="210" y="523" rx="0" ry="0" width="52" height="24" />
62
-
<circle cx="210" cy="535" r="12" />
63
-
<circle cx="428" cy="536" r="12" />
64
-
</ContentLoader>
65
-
)}
43
+
{isLoading && (
44
+
<ContentLoader
45
+
width={800}
46
+
height={575}
47
+
viewBox="0 0 800 575"
48
+
backgroundColor="var(--color-skeleton-background)"
49
+
foregroundColor="var(--color-skeleton-foreground)"
50
+
>
51
+
<rect x="12" y="9" rx="2" ry="2" width="140" height="10" />
52
+
<rect x="14" y="30" rx="2" ry="2" width="667" height="11" />
53
+
<rect x="12" y="58" rx="2" ry="2" width="211" height="211" />
54
+
<rect x="240" y="57" rx="2" ry="2" width="211" height="211" />
55
+
<rect x="467" y="56" rx="2" ry="2" width="211" height="211" />
56
+
<rect x="12" y="283" rx="2" ry="2" width="211" height="211" />
57
+
<rect x="240" y="281" rx="2" ry="2" width="211" height="211" />
58
+
<rect x="468" y="279" rx="2" ry="2" width="211" height="211" />
59
+
<circle cx="286" cy="536" r="12" />
60
+
<circle cx="319" cy="535" r="12" />
61
+
<circle cx="353" cy="535" r="12" />
62
+
<rect x="378" y="524" rx="0" ry="0" width="52" height="24" />
63
+
<rect x="210" y="523" rx="0" ry="0" width="52" height="24" />
64
+
<circle cx="210" cy="535" r="12" />
65
+
<circle cx="428" cy="536" r="12" />
66
+
</ContentLoader>
67
+
)}
66
68
67
-
{!isLoading && (
68
-
<div className="pb-[100px]">
69
-
<FlexGrid
70
-
flexGridColumnCount={[1, 2, 3]}
71
-
flexGridColumnGap="scale800"
72
-
flexGridRowGap="scale800"
73
-
>
74
-
{
75
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
76
-
data.map((song: any) => (
77
-
<FlexGridItem {...itemProps} key={song.id}>
78
-
<Link
79
-
to="/$did/scrobble/$rkey"
80
-
params={{
81
-
did: song.uri?.split("at://")[1]?.split("/")[0] || "",
82
-
rkey: song.uri?.split("/").pop() || "",
83
-
}}
84
-
>
85
-
<SongCover
86
-
cover={song.cover}
87
-
artist={song.artist}
88
-
title={song.title}
89
-
/>
90
-
</Link>
91
-
<Handle link={`/profile/${song.user}`} did={song.user} />{" "}
92
-
<LabelMedium className="!text-[var(--color-text-primary)]">
93
-
recently played this song
94
-
</LabelMedium>
95
-
<StatefulTooltip
96
-
content={dayjs(song.date).format(
97
-
"MMMM D, YYYY [at] HH:mm A",
98
-
)}
99
-
returnFocus
100
-
autoFocus
101
-
>
102
-
<LabelMedium className="!text-[var(--color-text-muted)]">
103
-
{dayjs(song.date).fromNow()}
104
-
</LabelMedium>
105
-
</StatefulTooltip>
106
-
</FlexGridItem>
107
-
))
108
-
}
109
-
</FlexGrid>
110
-
</div>
111
-
)}
112
-
</Container>
113
-
);
69
+
{!isLoading && (
70
+
<div className="pb-[100px]">
71
+
<FlexGrid
72
+
flexGridColumnCount={[1, 2, 3]}
73
+
flexGridColumnGap="scale800"
74
+
flexGridRowGap="scale1000"
75
+
>
76
+
{
77
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+
data.map((song: any) => (
79
+
<FlexGridItem {...itemProps} key={song.id}>
80
+
<Link
81
+
to="/$did/scrobble/$rkey"
82
+
params={{
83
+
did: song.uri?.split("at://")[1]?.split("/")[0] || "",
84
+
rkey: song.uri?.split("/").pop() || "",
85
+
}}
86
+
>
87
+
<SongCover
88
+
cover={song.cover}
89
+
artist={song.artist}
90
+
title={song.title}
91
+
/>
92
+
</Link>
93
+
<div className="flex">
94
+
<div className="mr-[8px]">
95
+
<Avatar
96
+
src={song.userAvatar}
97
+
name={song.userDisplayName}
98
+
size={"20px"}
99
+
/>
100
+
</div>
101
+
<Handle
102
+
link={`/profile/${song.user}`}
103
+
did={song.user}
104
+
/>{" "}
105
+
</div>
106
+
<LabelSmall className="!text-[var(--color-text-primary)]">
107
+
recently played this song
108
+
</LabelSmall>
109
+
<StatefulTooltip
110
+
content={dayjs(song.date).format(
111
+
"MMMM D, YYYY [at] HH:mm A",
112
+
)}
113
+
returnFocus
114
+
autoFocus
115
+
>
116
+
<LabelSmall className="!text-[var(--color-text-muted)]">
117
+
{dayjs(song.date).fromNow()}
118
+
</LabelSmall>
119
+
</StatefulTooltip>
120
+
</FlexGridItem>
121
+
))
122
+
}
123
+
</FlexGrid>
124
+
</div>
125
+
)}
126
+
</Container>
127
+
);
114
128
}
115
129
116
130
export default Feed;
History
1 round
0 comments
tsiry-sandratraina.com
submitted
#0
1 commit
expand
collapse
feat: display user avatar at the bottom of each scrobble
expand 0 comments
pull request successfully merged