Skip to content

Commit ad439ef

Browse files
committed
Resolved merge conflicts
2 parents 015854d + 1697cb7 commit ad439ef

File tree

7 files changed

+615
-0
lines changed

7 files changed

+615
-0
lines changed

Bookmark Visualizers/background.js

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
3535
return true; // Will respond asynchronously
3636
}
3737
});
38+
<<<<<<< HEAD
3839
//installion of extension
3940
chrome.runtime.onInstalled.addListener(() => {
4041
console.log("Extension installed");
@@ -45,3 +46,5 @@ chrome.runtime.onInstalled.addListener(() => {
4546
});
4647
});
4748
});
49+
=======
50+
>>>>>>> 1697cb79b9354499f359b54b7b0bdf9362800335

Bookmark Visualizers/logo.png

9.84 KB
Loading

Bookmark Visualizers/manifest.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"manifest_version": 3,
3+
"name": "Visual Bookmark Gallery",
4+
"version": "1.0",
5+
"description": "A visual gallery for your bookmarks with insights and sharing capabilities.",
6+
"permissions": ["bookmarks", "history", "storage", "tabs"],
7+
"background": {
8+
"service_worker": "background.js"
9+
},
10+
"action": {
11+
"default_popup": "popup.html",
12+
"default_icon": {
13+
"16": "logo.png",
14+
"48": "logo.png",
15+
"128": "logo.png"
16+
}
17+
},
18+
"icons": {
19+
"16": "logo.png",
20+
"48": "logo.png",
21+
"128": "logo.png"
22+
},
23+
"content_security_policy": {
24+
"extension_pages": "script-src 'self'; object-src 'self'"
25+
}
26+
}

Bookmark Visualizers/popup.html

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Visual Bookmark Gallery</title>
7+
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
8+
<link rel="stylesheet" href="styles.css">
9+
</head>
10+
<body>
11+
<div id="theme-toggle-container">
12+
<button id="theme-toggle-button">Toggle Dark Mode</button>
13+
</div>
14+
<div id="search-container">
15+
<input type="text" id="search-bar" placeholder="Search bookmarks..." />
16+
</div>
17+
<div id="gallery"></div>
18+
<script src="popup.js"></script>
19+
</body>
20+
</html>

Bookmark Visualizers/popup.js

+283
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
document.addEventListener("DOMContentLoaded", () => {
2+
const gallery = document.getElementById("gallery");
3+
const searchBar = document.getElementById("search-bar");
4+
const themeToggleButton = document.getElementById("theme-toggle-button");
5+
6+
// Load theme preference from local storage
7+
chrome.storage.local.get("darkMode", (data) => {
8+
if (data.darkMode) {
9+
document.body.classList.add("dark-mode");
10+
themeToggleButton.textContent = "Toggle Light Mode";
11+
}
12+
});
13+
14+
// Theme toggle button event listener
15+
themeToggleButton.addEventListener("click", () => {
16+
document.body.classList.toggle("dark-mode");
17+
const isDarkMode = document.body.classList.contains("dark-mode");
18+
themeToggleButton.textContent = isDarkMode
19+
? "Toggle Light Mode"
20+
: "Toggle Dark Mode";
21+
22+
// Save theme preference in local storage
23+
chrome.storage.local.set({ darkMode: isDarkMode });
24+
});
25+
26+
// Load bookmarks and usage data
27+
chrome.storage.local.get(
28+
["bookmarkUsage", "bookmarks", "customThumbnails"],
29+
(data) => {
30+
const usageData = data.bookmarkUsage || {};
31+
const customThumbnails = data.customThumbnails || {};
32+
const bookmarks = data.bookmarks[0].children; // Top-level bookmarks and folders
33+
let allBookmarks = [];
34+
35+
function traverseBookmarks(bookmarkNodes) {
36+
bookmarkNodes.forEach((bookmark) => {
37+
if (bookmark.url) {
38+
allBookmarks.push(bookmark);
39+
} else if (bookmark.children) {
40+
traverseBookmarks(bookmark.children);
41+
}
42+
});
43+
}
44+
45+
traverseBookmarks(bookmarks);
46+
47+
// Detect broken and duplicate bookmarks
48+
function detectIssues(bookmarks) {
49+
const duplicates = new Set();
50+
const uniqueUrls = new Set();
51+
const brokenBookmarks = [];
52+
53+
bookmarks.forEach((bookmark) => {
54+
if (uniqueUrls.has(bookmark.url)) {
55+
duplicates.add(bookmark);
56+
} else {
57+
uniqueUrls.add(bookmark.url);
58+
// Check if the bookmark is reachable
59+
chrome.runtime.sendMessage(
60+
{ action: "checkUrl", url: bookmark.url },
61+
(response) => {
62+
if (!response.ok) {
63+
brokenBookmarks.push(bookmark);
64+
}
65+
66+
// Display suggestions after all URLs are checked
67+
if (bookmarks.indexOf(bookmark) === bookmarks.length - 1) {
68+
displayCleanupSuggestions(duplicates, brokenBookmarks);
69+
}
70+
}
71+
);
72+
}
73+
});
74+
75+
if (duplicates.size > 0 || brokenBookmarks.length > 0) {
76+
displayCleanupSuggestions(duplicates, brokenBookmarks);
77+
}
78+
}
79+
80+
function displayCleanupSuggestions(duplicates, brokenBookmarks) {
81+
const cleanupContainer = document.createElement("div");
82+
cleanupContainer.classList.add("cleanup-suggestions");
83+
cleanupContainer.innerHTML = "<h3>Cleanup Suggestions</h3>";
84+
85+
if (duplicates.size > 0) {
86+
cleanupContainer.innerHTML += "<p>Duplicate Bookmarks:</p><ul>";
87+
duplicates.forEach((bookmark) => {
88+
cleanupContainer.innerHTML += `<li>${bookmark.title} - <a href="${bookmark.url}" target="_blank">${bookmark.url}</a></li>`;
89+
});
90+
cleanupContainer.innerHTML += "</ul>";
91+
}
92+
93+
if (brokenBookmarks.length > 0) {
94+
cleanupContainer.innerHTML += "<p>Broken Bookmarks:</p><ul>";
95+
brokenBookmarks.forEach((bookmark) => {
96+
cleanupContainer.innerHTML += `<li>${bookmark.title} - <a href="${bookmark.url}" target="_blank">${bookmark.url}</a></li>`;
97+
});
98+
cleanupContainer.innerHTML += "</ul>";
99+
}
100+
101+
gallery.appendChild(cleanupContainer);
102+
}
103+
104+
detectIssues(allBookmarks);
105+
106+
// Function to display recommendations
107+
function displayRecommendations(bookmark, container) {
108+
const recommendations = getRecommendations(bookmark);
109+
if (recommendations.length > 0) {
110+
const recommendationContainer = document.createElement("div");
111+
recommendationContainer.classList.add("recommendations");
112+
recommendationContainer.innerHTML = "<h4>Recommended Bookmarks</h4>";
113+
recommendations.forEach((rec) => {
114+
const recContainer = document.createElement("div");
115+
recContainer.classList.add("bookmark");
116+
117+
const img = document.createElement("img");
118+
img.src =
119+
customThumbnails[rec.id] ||
120+
`https://www.google.com/s2/favicons?domain=${rec.url}`;
121+
img.alt = rec.title;
122+
123+
const titleLink = document.createElement("a");
124+
titleLink.href = rec.url;
125+
titleLink.target = "_blank"; // Open in new tab
126+
titleLink.textContent = rec.title;
127+
titleLink.classList.add("title");
128+
129+
recContainer.appendChild(img);
130+
recContainer.appendChild(titleLink);
131+
recommendationContainer.appendChild(recContainer);
132+
});
133+
container.appendChild(recommendationContainer);
134+
}
135+
}
136+
137+
function getRecommendations(bookmark) {
138+
// Simple content-based recommendation system
139+
const recommendations = [];
140+
const threshold = 0.3; // Similarity threshold for recommendations
141+
allBookmarks.forEach((otherBookmark) => {
142+
if (
143+
bookmark.id !== otherBookmark.id &&
144+
calculateSimilarity(bookmark, otherBookmark) > threshold
145+
) {
146+
recommendations.push(otherBookmark);
147+
}
148+
});
149+
return recommendations.slice(0, 3); // Return top 3 recommendations
150+
}
151+
152+
function calculateSimilarity(bookmark1, bookmark2) {
153+
// Simple similarity calculation based on title and URL
154+
const titleSimilarity = getJaccardSimilarity(
155+
bookmark1.title,
156+
bookmark2.title
157+
);
158+
const urlSimilarity = getJaccardSimilarity(
159+
bookmark1.url,
160+
bookmark2.url
161+
);
162+
return (titleSimilarity + urlSimilarity) / 2;
163+
}
164+
165+
function getJaccardSimilarity(str1, str2) {
166+
const set1 = new Set(str1.toLowerCase().split(" "));
167+
const set2 = new Set(str2.toLowerCase().split(" "));
168+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
169+
const union = new Set([...set1, ...set2]);
170+
return intersection.size / union.size;
171+
}
172+
173+
function displayBookmarks(bookmarks) {
174+
gallery.innerHTML = ""; // Clear the gallery
175+
bookmarks.forEach((bookmark) => {
176+
const container = document.createElement("div");
177+
container.classList.add("bookmark");
178+
179+
const img = document.createElement("img");
180+
img.src =
181+
customThumbnails[bookmark.id] ||
182+
`https://www.google.com/s2/favicons?domain=${bookmark.url}`;
183+
img.alt = bookmark.title;
184+
img.addEventListener("click", () => customizeThumbnail(bookmark.id));
185+
186+
const titleLink = document.createElement("a");
187+
titleLink.href = bookmark.url;
188+
titleLink.target = "_blank"; // Open in new tab
189+
titleLink.textContent = bookmark.title;
190+
titleLink.classList.add("title");
191+
192+
const shareButton = document.createElement("button");
193+
shareButton.textContent = "Share";
194+
shareButton.classList.add("share-button");
195+
shareButton.setAttribute("data-url", bookmark.url);
196+
shareButton.addEventListener("click", () =>
197+
shareBookmark(shareButton)
198+
);
199+
200+
const usageInfo = usageData[bookmark.id] || {
201+
visits: 0,
202+
timeSpent: 0,
203+
};
204+
const usageText = document.createElement("div");
205+
usageText.classList.add("usage-info");
206+
usageText.innerHTML = `
207+
<div>Visits: ${usageInfo.visits}</div>
208+
<div>Time Spent: ${usageInfo.timeSpent} minutes</div>
209+
`;
210+
211+
container.appendChild(img);
212+
container.appendChild(titleLink);
213+
container.appendChild(shareButton);
214+
container.appendChild(usageText);
215+
gallery.appendChild(container);
216+
217+
// Display recommendations directly below the bookmark
218+
displayRecommendations(bookmark, gallery);
219+
});
220+
}
221+
222+
displayBookmarks(allBookmarks);
223+
224+
// Filter bookmarks based on search query
225+
searchBar.addEventListener("input", (event) => {
226+
const query = event.target.value.toLowerCase();
227+
const filteredBookmarks = allBookmarks.filter(
228+
(bookmark) =>
229+
bookmark.title.toLowerCase().includes(query) ||
230+
bookmark.url.toLowerCase().includes(query)
231+
);
232+
displayBookmarks(filteredBookmarks);
233+
});
234+
}
235+
);
236+
});
237+
238+
// Sharing function
239+
function shareBookmark(button) {
240+
const url = button.getAttribute("data-url");
241+
242+
// Share via Email
243+
const emailSubject = "Check out this bookmark!";
244+
const emailBody = `I wanted to share this bookmark with you: ${url}`;
245+
const mailtoLink = `mailto:?subject=${encodeURIComponent(
246+
emailSubject
247+
)}&body=${encodeURIComponent(emailBody)}`;
248+
249+
// Share via Social Media (e.g., Twitter)
250+
const twitterLink = `https://twitter.com/intent/tweet?url=${encodeURIComponent(
251+
url
252+
)}&text=Check%20out%20this%20bookmark!`;
253+
254+
// Optionally, show a UI for sharing choices
255+
const shareContainer = document.createElement("div");
256+
shareContainer.classList.add("share-options");
257+
shareContainer.innerHTML = `
258+
<a href="${mailtoLink}" target="_blank">Share via Email</a>
259+
<a href="${twitterLink}" target="_blank">Share on Twitter</a>
260+
`;
261+
button.parentNode.appendChild(shareContainer);
262+
}
263+
264+
// Custom Thumbnail function
265+
function customizeThumbnail(bookmarkId) {
266+
const input = document.createElement("input");
267+
input.type = "file";
268+
input.accept = "image/*";
269+
input.onchange = (event) => {
270+
const file = event.target.files[0];
271+
const reader = new FileReader();
272+
reader.onload = () => {
273+
const imgData = reader.result;
274+
chrome.storage.local.get("customThumbnails", (data) => {
275+
const customThumbnails = data.customThumbnails || {};
276+
customThumbnails[bookmarkId] = imgData;
277+
chrome.storage.local.set({ customThumbnails });
278+
});
279+
};
280+
reader.readAsDataURL(file);
281+
};
282+
input.click();
283+
}

0 commit comments

Comments
 (0)