A clean new tab page extension for Chrome, easy to grab and customize yourself.
browser-extensionchromechrome-extensioncsshandcodedhtmljavascriptnewtab
1/* ---------------------------------------------------------------------------*/
2/* 01 Time */
3/* ---------------------------------------------------------------------------*/
4
5let currentTimeElement = document.getElementById("currentTime");
6
7const updateTime = () => {
8 const currentTime = new Date();
9
10 let hours = currentTime.getHours();
11 if (hours > 12) {
12 hours -= 12;
13 }
14 if (hours === 0) {
15 hours = 12;
16 }
17
18 let minutes = currentTime.getMinutes();
19 if (minutes < 10) {
20 minutes = "0" + minutes;
21 }
22
23 const timeString = `${hours}:${minutes}`;
24 currentTimeElement.innerHTML = timeString;
25};
26
27updateTime();
28setInterval(updateTime, 1000);
29
30/* ---------------------------------------------------------------------------*/
31/* 02 Date */
32/* ---------------------------------------------------------------------------*/
33
34let currentDateElement = document.getElementById("currentDate");
35
36const updateDate = () => {
37 const currentDate = new Date();
38
39 let day = currentDate.getDay();
40 let month = currentDate.getMonth();
41 let dayOfMonth = currentDate.getDate();
42
43 const monthNames = [
44 "January",
45 "February",
46 "March",
47 "April",
48 "May",
49 "June",
50 "July",
51 "August",
52 "September",
53 "October",
54 "November",
55 "December",
56 ];
57
58 const dayNames = [
59 "Sunday",
60 "Monday",
61 "Tuesday",
62 "Wednesday",
63 "Thursday",
64 "Friday",
65 "Saturday",
66 ];
67
68 const dateString = `${dayNames[day]}, ${monthNames[month]} ${dayOfMonth}`;
69 currentDateElement.innerHTML = dateString;
70};
71
72updateDate();
73setInterval(updateDate, 1000);
74
75/* ---------------------------------------------------------------------------*/
76/* 03 Weather */
77/* ---------------------------------------------------------------------------*/
78
79const currentWeatherElement = document.getElementById("currentWeather");
80
81const fetchWeather = () => {
82 fetch(
83 "https://www.accuweather.com/en/us/morganton/28655/weather-forecast/334823"
84 )
85 .then((response) => response.text())
86 .then((html) => {
87 const parser = new DOMParser();
88 const doc = parser.parseFromString(html, "text/html");
89 const currentWeather = doc.querySelector(".forecast-container");
90
91 const weatherIcon = currentWeather.querySelector(".weather-icon");
92 weatherIcon.style.width = "128";
93 weatherIcon.style.height = "128";
94
95 const realFeel = currentWeather.querySelector(".real-feel");
96 realFeel.remove();
97
98 currentWeatherElement.innerHTML = currentWeather.innerHTML;
99
100 const currentWeatherString = currentWeather.innerHTML;
101 const currentWeatherObject = {
102 timestamp: Date.now(),
103 weather: currentWeatherString,
104 };
105 chrome.storage.local.set({ currentWeather: currentWeatherObject });
106 });
107};
108
109const getCurrentWeather = () => {
110 chrome.storage.local.get("currentWeather", (result) => {
111 const currentTimestamp = new Date();
112 if (result.currentWeather) {
113 if (currentTimestamp - result.currentWeather.timestamp < 1000 * 60 * 60) {
114 currentWeatherElement.innerHTML = result.currentWeather.weather;
115 return;
116 }
117 }
118 fetchWeather();
119 });
120};
121
122getCurrentWeather();
123setInterval(getCurrentWeather, 1000 * 60 * 60);
124
125/* ---------------------------------------------------------------------------*/
126/* 04 Posts */
127/* ---------------------------------------------------------------------------*/
128
129const currentPostsElement = document.getElementById("currentPosts");
130
131const getTopPosts = () => {
132 const currentPostsList = document.createElement("ul");
133 currentPostsElement.innerHTML = "";
134
135 fetch("https://hacker-news.firebaseio.com/v0/topstories.json")
136 .then((response) => response.json())
137 .then((json) => {
138 const topPosts = json.slice(0, 5);
139 const topPostsPromises = topPosts.map((id) => {
140 return fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json`)
141 .then((response) => response.json())
142 .then((json) => {
143 return json;
144 });
145 });
146 return Promise.all(topPostsPromises);
147 })
148 .then((topPosts) => {
149 topPosts.forEach((post) => {
150 const postElement = document.createElement("li");
151 const postLink = document.createElement("a");
152 postLink.href = `https://news.ycombinator.com/item?id=${post.id}`;
153
154 const postExtras = document.createElement("span");
155 postExtras.innerHTML = `<span>${post.score}</span>`;
156 postLink.appendChild(postExtras);
157
158 postLink.innerHTML += post.title;
159
160 postElement.appendChild(postLink);
161 currentPostsList.appendChild(postElement);
162 });
163 });
164
165 currentPostsElement.innerHTML = "";
166 currentPostsElement.appendChild(currentPostsList);
167};
168
169getTopPosts();
170
171/* ---------------------------------------------------------------------------*/
172/* 05 Bookmarks */
173/* ---------------------------------------------------------------------------*/
174
175const currentBookmarksElement = document.getElementById("currentBookmarks");
176
177const faviconFolder = `\
178<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="white" viewBox="0 0 16 16">
179 <path d="M9.828 3h3.982a2 2 0 0 1 1.992 2.181l-.637 7A2 2 0 0 1 13.174 14H2.825a2 2 0 0 1-1.991-1.819l-.637-7a1.99 1.99 0 0 1 .342-1.31L.5 3a2 2 0 0 1 2-2h3.672a2 2 0 0 1 1.414.586l.828.828A2 2 0 0 0 9.828 3zm-8.322.12C1.72 3.042 1.95 3 2.19 3h5.396l-.707-.707A1 1 0 0 0 6.172 2H2.5a1 1 0 0 0-1 .981l.006.139z"/>
180</svg>`;
181const faviconEdit = `\
182<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="white" viewBox="0 0 16 16">
183 <path d="M2 15.5a.5.5 0 0 0 .74.439L8 13.069l5.26 2.87A.5.5 0 0 0 14 15.5V2a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v13.5zM8 4.41c1.387-1.425 4.854 1.07 0 4.277C3.146 5.48 6.613 2.986 8 4.412z"/>
184</svg>`;
185const faviconDocument = `data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgZmlsbD0id2hpdGUiIHZpZXdCb3g9IjAgMCAxNiAxNiI+CiAgPHBhdGggZD0iTTkuMjkzIDBINGEyIDIgMCAwIDAtMiAydjEyYTIgMiAwIDAgMCAyIDJoOGEyIDIgMCAwIDAgMi0yVjQuNzA3QTEgMSAwIDAgMCAxMy43MDcgNEwxMCAuMjkzQTEgMSAwIDAgMCA5LjI5MyAwek05LjUgMy41di0ybDMgM2gtMmExIDEgMCAwIDEtMS0xek00LjUgOWEuNS41IDAgMCAxIDAtMWg3YS41LjUgMCAwIDEgMCAxaC03ek00IDEwLjVhLjUuNSAwIDAgMSAuNS0uNWg3YS41LjUgMCAwIDEgMCAxaC03YS41LjUgMCAwIDEtLjUtLjV6bS41IDIuNWEuNS41IDAgMCAxIDAtMWg0YS41LjUgMCAwIDEgMCAxaC00eiIvPgo8L3N2Zz4K`;
186
187const getBookmarks = () => {
188 try {
189 return chrome.bookmarks.getTree().then((bookmarks) => {
190 const children = bookmarks[0].children;
191 for (let i = 0; i < children.length; i++) {
192 if (children[i].title === "Bookmarks bar") {
193 return children[i].children;
194 }
195 }
196 });
197 } catch (e) {
198 console.log(e);
199 }
200};
201
202const addFavicon = (el, url) => {
203 const image = new Image();
204 image.src = url;
205 image.width = 14;
206 image.height = 14;
207 image.onload = () => {
208 el.prepend(image);
209 };
210 image.onerror = () => {
211 image.src = faviconDocument;
212 el.prepend(image);
213 };
214};
215
216const createBookmarksList = (bookmarks) => {
217 const bookmarksList = document.createElement("ul");
218 bookmarks.forEach((bookmark) => {
219 const bookmarkElement = document.createElement("li");
220 const bookmarkLink = document.createElement("a");
221
222 if (bookmark.url) {
223 const faviconUrl = new URL(bookmark.url).origin + "/favicon.ico";
224 addFavicon(bookmarkLink, faviconUrl);
225 bookmarkLink.href = bookmark.url;
226 } else {
227 bookmarkLink.href = "#";
228 const folderIcon = document.createElement("span");
229 folderIcon.innerHTML = faviconFolder;
230 bookmarkLink.appendChild(folderIcon);
231 }
232
233 bookmarkLink.innerHTML += bookmark.title;
234 bookmarkElement.appendChild(bookmarkLink);
235 bookmarksList.appendChild(bookmarkElement);
236 if (bookmark.children) {
237 const childrenList = createBookmarksList(bookmark.children);
238 bookmarkElement.appendChild(childrenList);
239 }
240 });
241 return bookmarksList;
242};
243
244const createBookmarksEditLink = () => {
245 const bookmarksList = document.createElement("ul");
246 const bookmarksListItem = document.createElement("li");
247 const bookmarksEditItemLink = document.createElement("a");
248 const bookmarksEditLinkIcon = document.createElement("span");
249
250 bookmarksEditItemLink.target = "_blank";
251 bookmarksEditItemLink.href = "chrome://bookmarks";
252 bookmarksEditItemLink.addEventListener("click", (e) => {
253 e.preventDefault();
254 chrome.tabs.create({ url: "chrome://bookmarks" });
255 });
256
257 bookmarksEditLinkIcon.innerHTML = faviconEdit;
258 bookmarksEditItemLink.appendChild(bookmarksEditLinkIcon);
259
260 bookmarksEditItemLink.innerHTML += "Edit";
261
262 bookmarksListItem.appendChild(bookmarksEditItemLink);
263 bookmarksList.appendChild(bookmarksListItem);
264
265 return bookmarksList;
266};
267
268const updateCurrentBookmarks = () => {
269 try {
270 getBookmarks().then((bookmarks) => {
271 currentBookmarksElement.innerHTML = "";
272 currentBookmarksElement.appendChild(createBookmarksList(bookmarks));
273 currentBookmarksElement.appendChild(createBookmarksEditLink());
274 });
275 } catch (e) {
276 console.log(e);
277 }
278};
279
280updateCurrentBookmarks();