├── .gitignore ├── .github └── preview.png ├── assets ├── icons │ ├── 16x16.png │ ├── 48x48.png │ ├── 64x64.png │ ├── 96x96.png │ └── 128x128.png ├── tabnews.svg ├── dailydev.svg ├── javascript.svg ├── favicon.svg ├── logo.svg └── scroll.svg ├── js ├── config.js ├── weather.js └── main.js ├── manifest.json ├── README.md ├── styles └── style.css └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_STORE -------------------------------------------------------------------------------- /.github/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birobirobiro/DevNews/HEAD/.github/preview.png -------------------------------------------------------------------------------- /assets/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birobirobiro/DevNews/HEAD/assets/icons/16x16.png -------------------------------------------------------------------------------- /assets/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birobirobiro/DevNews/HEAD/assets/icons/48x48.png -------------------------------------------------------------------------------- /assets/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birobirobiro/DevNews/HEAD/assets/icons/64x64.png -------------------------------------------------------------------------------- /assets/icons/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birobirobiro/DevNews/HEAD/assets/icons/96x96.png -------------------------------------------------------------------------------- /assets/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/birobirobiro/DevNews/HEAD/assets/icons/128x128.png -------------------------------------------------------------------------------- /js/config.js: -------------------------------------------------------------------------------- 1 | // Substitua a string abaixo com a sua chave de API do OpenWeatherMap, que você pode obter em https://openweathermap.org/api 2 | export const API_KEY = "b94fc3e6b8b15def8097fd39f888d555"; 3 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "DevNews", 4 | "version": "1.0", 5 | "description": "Suas notícias de programação em um só lugar", 6 | "icons": { 7 | "16": "/assets/icons/16x16.png", 8 | "48": "/assets/icons/48x48.png", 9 | "64": "/assets/icons/64x64.png", 10 | "96": "/assets/icons/96x96.png", 11 | "128": "/assets/icons/128x128.png" 12 | }, 13 | "chrome_url_overrides": { 14 | "newtab": "index.html" 15 | }, 16 | "permissions": ["geolocation"] 17 | } 18 | -------------------------------------------------------------------------------- /assets/tabnews.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /assets/dailydev.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

DevNews

2 | 3 |

4 | 5 |

6 | 7 | ## 🚀 Tecnologias 8 | 9 | Esse projeto foi desenvolvido com as seguintes tecnologias: 10 | 11 | - HTML 12 | - CSS 13 | - JavaScript 14 | 15 | ## 🌍 Acesse o site: 16 | 17 | - [https://devnews.birobirobiro.dev](https://devnews.birobirobiro.dev) 18 | 19 | ## 🚧 Instalação da extensão: 20 | 21 | - Baixe o [.zip](https://github.com/birobirobiro/dev-news/archive/refs/heads/master.zip) 22 | - Extraia em uma pasta em seu computador 23 | - No Google Chrome acesse a página [chrome://extensions/](chrome://extensions/) 24 | - Ative o modo de desenvolvedor 25 | - Clique em Load Unpacked 26 | - Escolha a pasta extraída e pronto 27 | 28 | --- 29 | 30 | Feito com ♥ by [birobirobiro](https://birobirobiro.dev) 31 | -------------------------------------------------------------------------------- /assets/javascript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /js/weather.js: -------------------------------------------------------------------------------- 1 | import { API_KEY } from "./config.js"; 2 | 3 | const greeting = document.getElementById("greeting"); 4 | const data = document.getElementById("data"); 5 | const hora = document.getElementById("hora"); 6 | const previsaoTempo = document.getElementById("previsao-tempo"); 7 | 8 | const now = new Date(); 9 | const dateNow = now.getHours(); 10 | 11 | window.onload = function () { 12 | // Define a saudação com base na hora atual 13 | if (dateNow >= 5 && dateNow < 12) { 14 | greeting.textContent = "Bom dia! Hoje é"; 15 | } else if (dateNow >= 12 && dateNow < 18) { 16 | greeting.textContent = "Boa tarde! Hoje é"; 17 | } else { 18 | greeting.textContent = "Boa noite! Hoje é"; 19 | } 20 | 21 | // Exibe a data e hora atual 22 | data.textContent = now.toLocaleDateString("pt-BR", { 23 | weekday: "long", 24 | }); 25 | 26 | hora.textContent = now.toLocaleTimeString("pt-BR", { 27 | hour: "2-digit", 28 | minute: "2-digit", 29 | }); 30 | 31 | previsaoTempo.textContent = "Carregando previsão do tempo..."; 32 | 33 | if ("geolocation" in navigator) { 34 | navigator.geolocation.getCurrentPosition( 35 | (position) => { 36 | 37 | // Para usar a localização do navegador, descomente esse código 38 | const latitude = position.coords.latitude; 39 | const longitude = position.coords.longitude; 40 | 41 | // Latitude e longitude de São Paulo 42 | // const latitude = -23.5489; 43 | // const longitude = -46.6388; 44 | 45 | fetch( 46 | `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${API_KEY}&lang=pt_br&units=metric` 47 | ) 48 | .then((response) => response.json()) 49 | .then((data) => { 50 | const description = data.weather[0].description; 51 | const descriptionCapitalized = 52 | description.charAt(0).toUpperCase() + description.slice(1); 53 | const temp = data.main.temp; 54 | const tempFormatted = temp.toFixed(0); 55 | const city = data.name; 56 | const weatherIconCode = data.weather[0].icon; 57 | const weatherIconUrl = `https://openweathermap.org/img/wn/${weatherIconCode}.png`; 58 | 59 | previsaoTempo.innerHTML = ` 60 |
61 | ${descriptionCapitalized} ${descriptionCapitalized} e temperatura de ${tempFormatted}°C em ${city} 62 |
`; 63 | }) 64 | 65 | .catch((error) => { 66 | console.error(error); 67 | previsaoTempo.textContent = 68 | "Não foi possível obter a previsão do tempo"; 69 | }); 70 | }, 71 | 72 | (error) => { 73 | console.error(error); 74 | previsaoTempo.textContent = "Não foi possível obter a localização"; 75 | } 76 | ); 77 | } else { 78 | previsaoTempo.textContent = "Geolocalização não suportada pelo navegador"; 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | function GithubTrending() { 2 | fetch("https://api.hackertab.dev/data/v2/github/global/daily.json") 3 | .then((response) => response.json()) 4 | .then((data) => { 5 | const githubSection = document.querySelector("#github .scroll"); 6 | const content = data 7 | .map( 8 | (item) => ` 9 |
10 | 11 |

${item.title}: ${item.description}

12 |
13 |
14 | ` 15 | ) 16 | .join(""); 17 | githubSection.innerHTML = content; 18 | }) 19 | .catch((error) => console.error(error)); 20 | } 21 | 22 | function ProductHunt() { 23 | fetch("https://api.hackertab.dev/data/v2/producthunt.json") 24 | .then((response) => response.json()) 25 | .then((data) => { 26 | const producthuntSection = document.querySelector( 27 | "#product-hunt .scroll" 28 | ); 29 | const content = data 30 | .map( 31 | (item) => ` 32 |
33 | 34 |

${item.title}: ${item.description}

35 |
36 |
37 | ` 38 | ) 39 | .join(""); 40 | producthuntSection.innerHTML = content; 41 | }) 42 | .catch((error) => console.error(error)); 43 | } 44 | 45 | function Medium() { 46 | fetch("https://api.hackertab.dev/data/v2/medium/javascript.json") 47 | .then((response) => response.json()) 48 | .then((data) => { 49 | const mediumSection = document.querySelector("#medium .scroll"); 50 | const content = data 51 | .map( 52 | (item) => ` 53 |
54 | 55 |

${item.title}

56 |
57 |
58 | ` 59 | ) 60 | .join(""); 61 | mediumSection.innerHTML = content; 62 | }) 63 | .catch((error) => console.error(error)); 64 | } 65 | 66 | function TabNews() { 67 | fetch("https://www.tabnews.com.br/api/v1/contents?strategy=relevant") 68 | .then((response) => response.json()) 69 | .then((data) => { 70 | const tabnewsSection = document.querySelector("#tabnews .scroll"); 71 | const content = data 72 | .map( 73 | (item) => ` 74 |
75 | 76 |

${item.title}

77 |
78 |
79 | ` 80 | ) 81 | .join(""); 82 | tabnewsSection.innerHTML = content; 83 | }) 84 | .catch((error) => console.error(error)); 85 | } 86 | 87 | function setCookie(name, value, days) { 88 | const date = new Date(); 89 | date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); 90 | const expires = "expires=" + date.toUTCString(); 91 | document.cookie = name + "=" + value + ";" + expires + ";path=/"; 92 | } 93 | 94 | function getCookie(name) { 95 | const cookieName = name + "="; 96 | const cookies = document.cookie.split(";"); 97 | for (let i = 0; i < cookies.length; i++) { 98 | let cookie = cookies[i]; 99 | while (cookie.charAt(0) == " ") { 100 | cookie = cookie.substring(1); 101 | } 102 | if (cookie.indexOf(cookieName) == 0) { 103 | return cookie.substring(cookieName.length, cookie.length); 104 | } 105 | } 106 | return ""; 107 | } 108 | 109 | // function DailyDev() { 110 | // fetch("https://cors-everywhere.onrender.com/https://dailydev.up.railway.app/") 111 | // .then((response) => response.json()) 112 | // .then((data) => { 113 | // const dailydevSection = document.querySelector("#dailydev .scroll"); 114 | // const content = data 115 | // .map( 116 | // (item) => ` 117 | //
118 | // 119 | //

${item.title}

120 | //
121 | //
122 | // ` 123 | // ) 124 | // .join(""); 125 | // dailydevSection.innerHTML = content; 126 | 127 | // // Salvar dados no cookie 128 | // setCookie("dailydevData", JSON.stringify(data), 1); // 1 dia de duração do cookie 129 | // }) 130 | // .catch((error) => console.error(error)); 131 | // } 132 | 133 | // Função para carregar dados do cookie e chamar a função DailyDev() 134 | function loadFromCookie() { 135 | const data = getCookie("dailydevData"); 136 | if (data) { 137 | const parsedData = JSON.parse(data); 138 | const dailydevSection = document.querySelector("#dailydev .scroll"); 139 | const content = parsedData 140 | .map( 141 | (item) => ` 142 |
143 | 144 |

${item.title}

145 |
146 |
147 | ` 148 | ) 149 | .join(""); 150 | dailydevSection.innerHTML = content; 151 | } 152 | } 153 | 154 | GithubTrending(); 155 | Medium(); 156 | ProductHunt(); 157 | TabNews(); 158 | // DailyDev(); 159 | -------------------------------------------------------------------------------- /styles/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | --background-color: #303446; 9 | --text-color: #c6d0f5; 10 | --border: 1px solid #c6d0f5; 11 | --news-title: #51576d; 12 | } 13 | 14 | body { 15 | font-family: "Fira Code", monospace; 16 | color: var(--text-color); 17 | background-color: var(--background-color); 18 | margin: 1rem; 19 | overflow: hidden; 20 | } 21 | 22 | input { 23 | background-color: transparent; 24 | border: var(--border); 25 | border-radius: 1rem; 26 | padding: 0.5rem; 27 | text-align: center; 28 | color: var(--text-color); 29 | } 30 | 31 | a { 32 | color: var(--text-color); 33 | text-decoration: none; 34 | } 35 | 36 | i { 37 | color: var(--text-color); 38 | } 39 | 40 | nav { 41 | display: flex; 42 | align-items: center; 43 | justify-content: space-between; 44 | } 45 | 46 | main { 47 | display: flex; 48 | flex-wrap: wrap; 49 | flex-direction: column; 50 | 51 | height: 100vh; 52 | overflow-x: auto; 53 | overflow-y: hidden; 54 | 55 | scroll-snap-type: x mandatory; 56 | gap: 1rem; 57 | margin-bottom: 5rem; 58 | } 59 | 60 | main>section { 61 | scroll-snap-align: center; 62 | scroll-snap-stop: always; 63 | } 64 | 65 | .info-weather { 66 | display: flex; 67 | align-items: center; 68 | justify-content: center; 69 | gap: 0.1rem; 70 | font-size: 0.8rem; 71 | } 72 | 73 | .info-weather img { 74 | display: none; 75 | } 76 | 77 | .search { 78 | display: flex; 79 | justify-content: center; 80 | } 81 | 82 | .hand { 83 | display: flex; 84 | justify-content: center; 85 | padding: 2rem; 86 | animation: handMove 1.5s infinite; 87 | } 88 | 89 | .news { 90 | align-items: center; 91 | border: var(--border); 92 | border-radius: 1rem; 93 | overflow-y: scroll; 94 | margin-top: 0.5rem; 95 | width: 100%; 96 | max-height: 500px; 97 | } 98 | 99 | .news .title { 100 | display: flex; 101 | align-items: center; 102 | text-align: center; 103 | gap: 0.5rem; 104 | padding: 0.5rem; 105 | border-bottom: var(--border); 106 | } 107 | 108 | .title i, 109 | .title span { 110 | color: var(--news-title); 111 | font-size: 1.5rem; 112 | font-weight: 500; 113 | } 114 | 115 | .news>div { 116 | display: flex; 117 | justify-content: center; 118 | width: 100%; 119 | } 120 | 121 | .scroll { 122 | display: flex; 123 | flex-direction: column; 124 | overflow-y: auto; 125 | overflow-x: hidden; 126 | } 127 | 128 | .row-news { 129 | display: flex; 130 | flex-direction: column; 131 | width: 100%; 132 | border-bottom: var(--border); 133 | border-radius: 0.1rem; 134 | padding: 0.5rem; 135 | word-wrap: break-word; 136 | } 137 | 138 | .row-news:last-child { 139 | border-bottom: none; 140 | } 141 | 142 | .row-news p { 143 | font-size: 1rem; 144 | } 145 | 146 | footer a { 147 | display: flex; 148 | align-items: center; 149 | font-size: 1rem; 150 | text-align: center; 151 | justify-content: center; 152 | margin-top: 2rem; 153 | gap: 0.4rem; 154 | } 155 | 156 | .greeting-container { 157 | display: flex; 158 | flex-direction: column; 159 | justify-content: center; 160 | align-items: center; 161 | margin: 3rem 0; 162 | font-family: "Poppins", sans-serif; 163 | color: #a5adce; 164 | } 165 | 166 | .greeting-box { 167 | display: flex; 168 | gap: 0.2rem; 169 | text-align: center; 170 | } 171 | 172 | @keyframes handMove { 173 | 0% { 174 | transform: translateX(0); 175 | } 176 | 177 | 50% { 178 | transform: translateX(10px); 179 | } 180 | 181 | 100% { 182 | transform: translateX(-10px); 183 | } 184 | } 185 | 186 | @media (min-width: 300px) { 187 | main { 188 | height: 50vh; 189 | margin: 2rem 0 4rem 0; 190 | } 191 | 192 | main::-webkit-scrollbar { 193 | display: none; 194 | } 195 | 196 | nav { 197 | justify-content: center; 198 | } 199 | 200 | input, 201 | .logo { 202 | display: none; 203 | } 204 | 205 | .greeting-container { 206 | font-size: 0.9rem; 207 | gap: 0.5rem; 208 | text-align: center; 209 | margin: 2rem 0; 210 | } 211 | 212 | .greeting-box span { 213 | font-size: 1rem; 214 | } 215 | 216 | .hand { 217 | padding: 0.5rem 0; 218 | } 219 | } 220 | 221 | @media (min-width: 920px) { 222 | main::-webkit-scrollbar { 223 | display: none; 224 | } 225 | 226 | input { 227 | width: 20rem; 228 | } 229 | 230 | nav { 231 | justify-content: space-between; 232 | } 233 | 234 | input, 235 | .logo { 236 | display: block; 237 | } 238 | 239 | #hour, 240 | #previsao-tempo { 241 | display: block; 242 | } 243 | 244 | .info-weather { 245 | font-size: 0.9rem; 246 | } 247 | 248 | .info-weather img { 249 | display: block; 250 | } 251 | } 252 | 253 | @media (min-width: 1024px) { 254 | .container { 255 | margin: 1rem auto; 256 | width: 90%; 257 | } 258 | 259 | .greeting-container { 260 | margin: 4rem 0; 261 | } 262 | 263 | main { 264 | flex-direction: row; 265 | flex-wrap: nowrap; 266 | } 267 | 268 | input { 269 | width: 30rem; 270 | } 271 | 272 | .hand { 273 | display: none; 274 | } 275 | 276 | .logo { 277 | position: relative; 278 | width: 100px; 279 | } 280 | 281 | .logo img { 282 | position: absolute; 283 | right: 0; 284 | top: 50%; 285 | transform: translateY(-50%); 286 | } 287 | } 288 | 289 | @media (min-width: 2500px) { 290 | body { 291 | overflow: scroll; 292 | } 293 | 294 | .container { 295 | margin: 2rem auto; 296 | width: 90%; 297 | height: 90%; 298 | } 299 | 300 | main, 301 | .greeting-container, 302 | footer { 303 | margin: 10rem auto; 304 | } 305 | } 306 | 307 | /* ===== Scrollbar CSS ===== */ 308 | /* Firefox */ 309 | * { 310 | scrollbar-width: auto; 311 | scrollbar-color: #798595; 312 | } 313 | 314 | /* Chrome, Edge, and Safari */ 315 | *::-webkit-scrollbar { 316 | width: 5px; 317 | } 318 | 319 | *::-webkit-scrollbar-track { 320 | background: transparent; 321 | } 322 | 323 | .news::-webkit-scrollbar-track { 324 | margin-block-start: 3rem; 325 | margin-block-end: 0.5rem; 326 | } 327 | 328 | *::-webkit-scrollbar-thumb { 329 | background-color: #798595; 330 | border-radius: 5px; 331 | } 332 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DevNews 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 53 | 55 | 56 | 57 | 58 |
59 | 76 | 77 |
78 |
79 | 80 | 81 | 82 |
83 |
84 | 85 | 86 |
87 |
88 | 89 |
90 |
91 |
92 | tabnews 93 | 94 | TabNews 95 | 96 |
97 | 98 |
99 | 100 |
101 |
102 | 103 |
104 |
105 | 106 | 107 | GitHub 108 | 109 |
110 | 111 |
112 | 113 |
114 |
115 | 116 |
117 |
118 | 119 | 120 | Product Hunt 121 | 122 |
123 | 124 |
125 | 126 |
127 |
128 | 129 |
130 |
131 | 132 | 133 | Medium 134 | 135 |
136 | 137 |
138 | 139 |
140 |
141 | 142 | 153 |
154 | 155 |
156 | scroll 157 |
158 | 159 | 169 |
170 | 171 | 172 | -------------------------------------------------------------------------------- /assets/scroll.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------