Skip to content

Commit f7e40e8

Browse files
committed
[IMP] Import/Export Bookmarks
This commit adds functionality of importing/exporting your personal bookmarks. It can help to share your bookmarks with your friends or get their bookmarks too.
1 parent 16e55a9 commit f7e40e8

File tree

2 files changed

+98
-9
lines changed

2 files changed

+98
-9
lines changed

src/features/settings/components/BookmarkSettings/BookmarkSettings.tsx

+70-9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useRef, useState } from 'react'
12
import { BiBookmarkMinus } from 'react-icons/bi'
23
import toast from 'react-simple-toasts'
34
import { CardLink } from 'src/components/Elements'
@@ -60,17 +61,77 @@ const BookmarkItem = ({ item, appendRef = false }: BookmarkItemProps) => {
6061
}
6162

6263
export const BookmarkSettings = () => {
63-
const { userBookmarks } = useBookmarks()
64+
const inputFile = useRef<HTMLInputElement | null>(null)
65+
const {initState, userBookmarks } = useBookmarks()
66+
67+
const importBookmarks = () => {
68+
inputFile.current?.click()
69+
}
70+
71+
const exportBookmarks = () => {
72+
const blob = new Blob([JSON.stringify(userBookmarks, null, 2)], {
73+
type: 'application/json',
74+
})
75+
const downloadURL = URL.createObjectURL(blob);
76+
const link = document.createElement("a");
77+
link.href = downloadURL;
78+
link.download = "hackertabBookmarks";
79+
link.click();
80+
}
81+
const handleFileChange = (event: any) => {
82+
const file = event.target.files?.[0];
83+
if (file && file.type === 'application/json') {
84+
const reader = new FileReader()
85+
reader.onload = () => {
86+
const importData: BookmarkedPost[] = JSON.parse(reader.result as string);
87+
const validatedData = importData.filter(
88+
(data: BookmarkedPost) =>
89+
data.title &&
90+
data.url &&
91+
!userBookmarks.some((bm) => bm.title === data.title && bm.url === data.url))
92+
.map((data) => ({
93+
title: data.title,
94+
url: data.url,
95+
source: data.source || '',
96+
sourceType: data.sourceType || '',
97+
}));
98+
initState({
99+
userBookmarks: [...userBookmarks, ...validatedData],
100+
});
101+
}
102+
reader.readAsText(file)
103+
}
104+
}
105+
64106

65107
return (
66-
<SettingsContentLayout
67-
title="Bookmarks"
68-
description="Find all your bookmarks here. You can remove a bookmark by clicking on the remove icon.">
69-
<div className="bookmarks">
70-
{userBookmarks.map((bm) => (
71-
<BookmarkItem item={bm} key={bm.url} />
72-
))}
108+
<>
109+
<div className="btn-group">
110+
<div>
111+
<input
112+
type="file"
113+
id="file"
114+
ref={inputFile}
115+
style={{ display: 'none' }}
116+
onChange={handleFileChange}
117+
/>
118+
<button className="notbtn btn" onClick={() => importBookmarks()}>
119+
Import
120+
</button>
121+
</div>
122+
<button className="notbtn btn" onClick={() => exportBookmarks()}>
123+
Export
124+
</button>
73125
</div>
74-
</SettingsContentLayout>
126+
<SettingsContentLayout
127+
title="Bookmarks"
128+
description="Find all your bookmarks here. You can remove a bookmark by clicking on the remove icon.">
129+
<div className="bookmarks">
130+
{userBookmarks.map((bm) => (
131+
<BookmarkItem item={bm} key={bm.url} />
132+
))}
133+
</div>
134+
</SettingsContentLayout>
135+
</>
75136
)
76137
}

src/features/settings/components/BookmarkSettings/bookmarkSettings.css

+28
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,31 @@
5353
align-items: center;
5454
justify-content: center;
5555
}
56+
57+
/* Export/Import Bookmark Buttons */
58+
59+
/* removing that ugly default button design */
60+
.notbtn {
61+
background: none;
62+
color: inherit;
63+
border: none;
64+
padding: 0;
65+
font: inherit;
66+
cursor: pointer;
67+
outline: inherit;
68+
}
69+
70+
.btn-group {
71+
padding: 10px;
72+
display: flex;
73+
}
74+
75+
.btn {
76+
border-radius: 12px;
77+
padding: 6px 12px;
78+
margin-right: 5px;
79+
background-color: var(--chip-background);
80+
}
81+
.btn:hover {
82+
filter: brightness(85%);
83+
}

0 commit comments

Comments
 (0)