Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions submissions/snippetify/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# snippetify
snippetify is a minimalistic browser extension that lets you highlight text (by selecting & right clicking) on webpages in pastel colors and locally save snippets of exactly what you highlighted with links for future reference. it has an option to edit the heading of each snippet so you can locate your snippet at a glance.

![image](https://github.com/user-attachments/assets/b0e25dde-d595-44f1-9361-9e783fe760b3)


[demo video here](https://hc-cdn.hel1.your-objectstorage.com/s/v3/4cf02f5a36d545e4c30c40afbdf24d6d88c9c763_browserbuddy-demo.mp4)
50 changes: 50 additions & 0 deletions submissions/snippetify/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: "saveSnippet",
title: "highlight text to save",
contexts: ["selection"]
});

chrome.storage.local.get("snippets", function (data) {
chrome.storage.local.set({ snippets: data.snippets || [] });
});
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId === "saveSnippet") {
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: highlightAndSave,
args: [info.selectionText, tab.url, tab.title]
});
}
});

function highlightAndSave(selectedText, url, pageTitle) {
let range = window.getSelection().getRangeAt(0);
let span = document.createElement("span");

let pastelColors = ["#FFDDEE", "#DDF0FF", "#E8DFFF", "#FFF4C2", "#DAF0CC", "#F0D9CC"];
let randomColor = pastelColors[Math.floor(Math.random() * pastelColors.length)];

span.textContent = selectedText;
span.style.backgroundColor = randomColor;
span.style.padding = "2px 4px";
span.style.borderRadius = "4px";
span.style.fontWeight = "500";

range.deleteContents();
range.insertNode(span);

chrome.storage.local.get({ snippets: [] }, function (data) {
let snippets = data.snippets;
snippets.push({
text: selectedText,
url: url,
color: randomColor,
heading: pageTitle || "New Snippet"
});
chrome.storage.local.set({ snippets: snippets });
});
}

9 changes: 9 additions & 0 deletions submissions/snippetify/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
chrome.storage.local.get("snippets", function (data) {
(data.snippets || []).forEach((snippet) => {
document.body.innerHTML = document.body.innerHTML.replace(
new RegExp(snippet.text, "g"),
`<span class="highlighted" style="background-color:${snippet.color};">${snippet.text}</span>`
);
});
});

Binary file added submissions/snippetify/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions submissions/snippetify/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"manifest_version": 3,
"name": "snippetify",
"version": "1.2",
"permissions": ["storage", "activeTab", "contextMenus", "scripting"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}

Binary file added submissions/snippetify/poppins.ttf
Binary file not shown.
11 changes: 11 additions & 0 deletions submissions/snippetify/popup.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#popup-container {
width: 300px;
height: 400px;
padding: 10px;
margin: 0;
background-color: white;
font-family: "Poppins", sans-serif;
border-radius: 8px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
overflow: auto;
}
17 changes: 17 additions & 0 deletions submissions/snippetify/popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>snippetify - saved snippets</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div class="container" id="popup-container">
<h2>🌱 saved snippets</h2>
<ul id="snippetList"></ul>
</div>
<script src="popup.js"></script>
</body>
</html>
90 changes: 90 additions & 0 deletions submissions/snippetify/popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
document.addEventListener("DOMContentLoaded", function () {
let snippetList = document.getElementById("snippetList");

chrome.storage.local.get("snippets", function (data) {
snippetList.innerHTML = "";

(data.snippets || []).forEach((snippet, index) => {
let li = document.createElement("li");
li.style.backgroundColor = snippet.color;
li.classList.add("snippet");

let headingInput = document.createElement("input");
headingInput.type = "text";
headingInput.value = snippet.heading;
headingInput.classList.add("heading-input");

headingInput.addEventListener("change", function () {
chrome.storage.local.get("snippets", function (data) {
let snippets = data.snippets || [];
snippets[index].heading = headingInput.value;
chrome.storage.local.set({ snippets: snippets });
});
});

// highlighted text container
let textContainer = document.createElement("div");
textContainer.classList.add("text-container");

let text = document.createElement("span");
text.classList.add("highlighted-text");

let fullText = snippet.text;
let truncatedText = fullText.length > 150 ? fullText.substring(0, 140) + "..." : fullText;
text.innerHTML = truncatedText;

let readMore = document.createElement("a");
readMore.textContent = " read more";
readMore.href = "#";
readMore.classList.add("read-more");
readMore.style.display = fullText.length > 150 ? "inline" : "none";

let isExpanded = false;
readMore.addEventListener("click", function (event) {
event.preventDefault();
isExpanded = !isExpanded;
text.innerHTML = isExpanded ? fullText : truncatedText;
readMore.textContent = isExpanded ? " read less" : " read more";
});

textContainer.appendChild(text);
// textContainer.appendChild(document.createElement("br"));
textContainer.appendChild(readMore);

// button container (stacked vertically)
let buttonContainer = document.createElement("div");
buttonContainer.classList.add("button-container");

let link = document.createElement("a");
link.href = snippet.url;
link.textContent = "🔗";
link.target = "_blank";
link.classList.add("icon-button");

let removeBtn = document.createElement("button");
removeBtn.textContent = "×";
removeBtn.classList.add("delete-btn");
removeBtn.onclick = function () {
chrome.storage.local.get("snippets", function (data) {
let snippets = data.snippets || [];
snippets.splice(index, 1);
chrome.storage.local.set({ snippets: snippets }, function () {
location.reload();
});
});
};

buttonContainer.appendChild(link);
buttonContainer.appendChild(removeBtn);

let snippetRow = document.createElement("div");
snippetRow.classList.add("snippet-row");
snippetRow.appendChild(textContainer);
snippetRow.appendChild(buttonContainer);

li.appendChild(headingInput);
li.appendChild(snippetRow);
snippetList.appendChild(li);
});
});
});
121 changes: 121 additions & 0 deletions submissions/snippetify/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
@font-face {
font-family: "Poppins";
src: url("poppins.ttf") format("truetype");
}

body {
font-family: "Poppins", sans-serif;
background: #dad7cd;
text-align: left;
padding: 20px;
border-radius: 10px;
}

.container {
background: white;
border-radius: 12px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
padding: 15px;
}

h2 {
font-size: 18px;
color: #333;
margin-bottom: 10px;
}

ul {
list-style: none;
padding: 0;
margin: 0;
}

.snippet {
font-weight: 500;
border-radius: 6px;
padding: 8px;
margin-bottom: 8px;
display: flex;
flex-direction: column;
align-items: flex-start;
position: relative;
}

.heading-input {
font-family: "Poppins", sans-serif;
font-size: 14px;
width: 100%;
border: none;
background: transparent;
font-weight: bold;
text-decoration: underline;
margin-bottom: 2px;
padding: 2px;
}

.heading-input:focus {
outline: none;
border-bottom: 1px solid #aaa;
}

.snippet-row {
display: flex;
justify-content: space-between;
width: 100%;
align-items: flex-start;
}

.text-container {
max-width: 75%;
display: flex;
flex-direction: column;
}

.highlighted-text {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
padding: 2px 6px;
border-radius: 4px;
font-weight: normal;
text-overflow: ellipsis;
}

.read-more {
font-size: 12px;
cursor: pointer;
font-weight: bold;
white-space: nowrap;
text-decoration: underline;
color: #555;
}

.read-more:hover {
text-decoration: underline;
color: #000;
}

.button-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}

.icon-button {
text-decoration: none;
font-size: 16px;
}

.delete-btn {
background: transparent;
border: none;
font-size: 16px;
cursor: pointer;
color: #777;
}

.delete-btn:hover {
color: red;
}