this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

more

+494 -19
+494 -19
index.html
··· 21 21 --header-height: 50px; 22 22 --sidebar-width: 80px; 23 23 --tab-height: 40px; 24 + --ripple-color: rgba(77, 250, 123, 0.04); 25 + --ripple-color-strong: rgba(77, 250, 123, 0.06); 26 + --matrix-color: rgba(77, 250, 123, 0.2); 27 + --matrix-glow: rgba(77, 250, 123, 0.1); 28 + --hover-glow: rgba(77, 250, 123, 0.15); 24 29 } 25 30 26 31 * { ··· 35 40 color: var(--text-color); 36 41 line-height: 1.5; 37 42 overflow-x: hidden; 43 + position: relative; 44 + } 45 + 46 + body::before { 47 + content: ''; 48 + position: fixed; 49 + top: 0; 50 + left: 0; 51 + width: 100%; 52 + height: 100%; 53 + background: linear-gradient(rgba(10, 23, 15, 0.82), rgba(10, 23, 15, 0.92)); 54 + z-index: -1; 55 + pointer-events: none; 56 + } 57 + 58 + #matrix-background { 59 + position: fixed; 60 + top: 0; 61 + left: 0; 62 + width: 100%; 63 + height: 100%; 64 + z-index: -2; 65 + opacity: 0.6; 66 + pointer-events: none; 38 67 } 39 68 40 69 header { ··· 368 397 369 398 .feed-item { 370 399 border-left: 3px solid transparent; 371 - transition: all 0.3s ease; 400 + transition: all 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); 401 + position: relative; 402 + overflow: hidden; 403 + z-index: 1; 372 404 } 373 405 374 406 .feed-item:hover { 375 407 border-left-color: var(--accent-color); 376 - background-color: rgba(77, 250, 123, 0.03); 408 + background-color: rgba(21, 39, 32, 0.95); 409 + } 410 + 411 + .feed-item::before { 412 + content: ''; 413 + position: absolute; 414 + top: 0; 415 + left: 0; 416 + right: 0; 417 + bottom: 0; 418 + background: radial-gradient(circle at var(--mouse-x, 0%) var(--mouse-y, 0%), 419 + rgba(77, 250, 123, 0.06) 0%, 420 + rgba(77, 250, 123, 0.04) 30%, 421 + rgba(77, 250, 123, 0) 70%); 422 + opacity: 0; 423 + z-index: 0; 424 + transform: scale(0); 425 + transition: opacity 0.5s ease, transform 0.7s cubic-bezier(0.19, 1, 0.22, 1); 426 + pointer-events: none; 377 427 } 378 428 379 429 .references-container { ··· 407 457 display: inline; 408 458 margin-left: 8px; 409 459 opacity: 1; 460 + } 461 + 462 + .feed-item:hover::before { 463 + opacity: 0.6; 464 + transform: scale(1.5); 410 465 } 411 466 412 467 .preview-links, ··· 618 673 border-radius: 4px; 619 674 margin-bottom: 8px; 620 675 overflow: hidden; 621 - transition: background-color 0.2s ease; 676 + transition: all 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); 622 677 display: flex; 623 678 align-items: center; 624 679 padding: 10px 15px; 680 + position: relative; 625 681 } 626 682 627 683 .link-item:hover { 628 - background-color: #1a3028; 684 + background-color: rgba(21, 39, 32, 0.95); 629 685 border-left-color: var(--accent-color); 630 686 } 631 687 688 + .link-item::before { 689 + content: ''; 690 + position: absolute; 691 + top: 0; 692 + left: 0; 693 + right: 0; 694 + bottom: 0; 695 + background: radial-gradient(circle at var(--mouse-x, 0%) var(--mouse-y, 0%), 696 + rgba(77, 250, 123, 0.06) 0%, 697 + rgba(77, 250, 123, 0.04) 30%, 698 + rgba(77, 250, 123, 0) 70%); 699 + opacity: 0; 700 + z-index: 0; 701 + transform: scale(0); 702 + transition: opacity 0.5s ease, transform 0.7s cubic-bezier(0.19, 1, 0.22, 1); 703 + pointer-events: none; 704 + } 705 + 706 + .link-item:hover::before { 707 + opacity: 0.6; 708 + transform: scale(1.5); 709 + } 710 + 632 711 .link-item-date { 633 712 font-family: 'JetBrains Mono', monospace; 634 713 font-size: 0.75rem; ··· 953 1032 </style> 954 1033 </head> 955 1034 <body> 1035 + <canvas id="matrix-background"></canvas> 956 1036 <header> 957 1037 <div class="header-container"> 958 1038 <div class="header-left"> ··· 989 1069 990 1070 <script> 991 1071 document.addEventListener('DOMContentLoaded', async () => { 1072 + // Matrix background effect 1073 + const canvas = document.getElementById('matrix-background'); 1074 + const ctx = canvas.getContext('2d'); 1075 + 1076 + // Set canvas size to match window 1077 + function resizeCanvas() { 1078 + canvas.width = window.innerWidth; 1079 + canvas.height = window.innerHeight; 1080 + } 1081 + resizeCanvas(); 1082 + window.addEventListener('resize', resizeCanvas); 1083 + 1084 + // Vine/plant-related characters and elements 1085 + const vineChars = '┃┃│┋┇┊┆╽╿┴┬╵╷└┕┖┗┘┙┚┛╘╙╚╛╯╰╱╲⌠⌡╎▏▕⏐▌▐░▒▓◥◤◢◣⎸⎹│'; 1086 + const leafChars = '☘❀✿❁❃❇❈❉❊❋✣✤✥✦✧✩✪✫✬✭✮✾✿❀❁❂❃❄⚘♠♣⚜⚘☘'; 1087 + const branchChars = '┌┐┘└├┬┴┤┼─┄┈┉┊┋╱╲╳☂⚢⌒~∞≈≋⋆✧✦✫'; 1088 + const fontSize = 14; 1089 + const columns = Math.floor(canvas.width / fontSize * 0.7); // Fewer columns for sparser vines 1090 + 1091 + // Drop positions for each column 1092 + const drops = []; 1093 + 1094 + // Initialize drops at random positions 1095 + for (let i = 0; i < columns; i++) { 1096 + // Random starting position 1097 + drops[i] = Math.random() * -canvas.height; 1098 + } 1099 + 1100 + // Set up column types - some will be vines, some will have leaves 1101 + const columnTypes = []; 1102 + for (let i = 0; i < columns; i++) { 1103 + // 70% of columns are vines, 25% are leaves, 5% are cross-connections 1104 + const rand = Math.random(); 1105 + if (rand < 0.7) { 1106 + columnTypes[i] = 'vine'; 1107 + } else if (rand < 0.95) { 1108 + columnTypes[i] = 'leaf'; 1109 + } else { 1110 + columnTypes[i] = 'branch'; 1111 + } 1112 + } 1113 + 1114 + // Store connections between vines 1115 + const connections = []; 1116 + 1117 + // Helper function to find nearby columns 1118 + function findNearbyColumns(columnIndex, maxDistance = 3) { 1119 + const nearby = []; 1120 + for (let i = 0; i < columns; i++) { 1121 + if (i !== columnIndex && Math.abs(i - columnIndex) <= maxDistance) { 1122 + nearby.push(i); 1123 + } 1124 + } 1125 + return nearby; 1126 + } 1127 + 1128 + // Last time random chars were changed 1129 + const lastCharChangeTime = []; 1130 + // The current characters displayed 1131 + const currentChars = []; 1132 + // Width/thickness of vines 1133 + const vineThickness = []; 1134 + 1135 + for (let i = 0; i < columns; i++) { 1136 + lastCharChangeTime[i] = []; 1137 + currentChars[i] = []; 1138 + 1139 + // Random vine thickness between 1-3 1140 + vineThickness[i] = Math.floor(Math.random() * 3) + 1; 1141 + 1142 + for (let j = 0; j < canvas.height / fontSize; j++) { 1143 + lastCharChangeTime[i][j] = 0; 1144 + 1145 + if (columnTypes[i] === 'vine') { 1146 + // Choose vine characters based on position and thickness 1147 + if (j === 0) { 1148 + // Top of vine - might be a leaf or flower 1149 + currentChars[i][j] = Math.random() < 0.6 ? 1150 + leafChars.charAt(Math.floor(Math.random() * leafChars.length)) : 1151 + vineChars.charAt(Math.floor(Math.random() * vineChars.length)); 1152 + } else { 1153 + // Main vine character 1154 + const vineIndex = Math.min(vineThickness[i] * 3, vineChars.length - 1); 1155 + currentChars[i][j] = vineChars.charAt(Math.floor(Math.random() * vineIndex)); 1156 + } 1157 + } else if (columnTypes[i] === 'leaf') { 1158 + // Leaf character - only at top or occasional spots along the vine 1159 + if (j === 0 || Math.random() < 0.2) { 1160 + currentChars[i][j] = leafChars.charAt(Math.floor(Math.random() * leafChars.length)); 1161 + } else { 1162 + // Connecting vine 1163 + currentChars[i][j] = vineChars.charAt(Math.floor(Math.random() * 5)); // Thin vine characters 1164 + } 1165 + } else if (columnTypes[i] === 'branch') { 1166 + // This is a branching column - will form connections between vines 1167 + if (j === 0) { 1168 + // Top of branch might be a leaf or flower 1169 + currentChars[i][j] = leafChars.charAt(Math.floor(Math.random() * leafChars.length)); 1170 + } else { 1171 + // Branch characters - horizontal or diagonal connectors 1172 + currentChars[i][j] = branchChars.charAt(Math.floor(Math.random() * branchChars.length)); 1173 + } 1174 + } 1175 + } 1176 + } 1177 + 1178 + // Time when animation started 1179 + const startTime = Date.now(); 1180 + 1181 + // Track connections between vines 1182 + const crossConnections = []; 1183 + 1184 + // Draw the rainforest vine effect 1185 + function drawVineEffect() { 1186 + // Semi-transparent background to create fade effect 1187 + ctx.fillStyle = 'rgba(10, 23, 15, 0.05)'; 1188 + ctx.fillRect(0, 0, canvas.width, canvas.height); 1189 + 1190 + const now = Date.now(); 1191 + 1192 + // Set font 1193 + ctx.font = `${fontSize}px 'JetBrains Mono', monospace`; 1194 + ctx.textAlign = 'center'; 1195 + 1196 + // First, create cross-connections 1197 + // Create new cross-connections occasionally 1198 + if (Math.random() < 0.01) { 1199 + // Find a source vine that's grown enough 1200 + const sourceIndex = Math.floor(Math.random() * columns); 1201 + if (drops[sourceIndex] > 100 && columnTypes[sourceIndex] === 'vine') { 1202 + // Find a nearby column to connect to 1203 + const nearby = findNearbyColumns(sourceIndex, 3); 1204 + if (nearby.length > 0) { 1205 + const targetIndex = nearby[Math.floor(Math.random() * nearby.length)]; 1206 + if (drops[targetIndex] > 80) { 1207 + // The height should be somewhere between the two vines 1208 + const sourceHeight = drops[sourceIndex]; 1209 + const targetHeight = drops[targetIndex]; 1210 + const connectionHeight = Math.min(sourceHeight, targetHeight) * 0.8; 1211 + 1212 + // Create the connection 1213 + crossConnections.push({ 1214 + source: sourceIndex, 1215 + target: targetIndex, 1216 + height: connectionHeight, 1217 + character: branchChars.charAt(Math.floor(Math.random() * branchChars.length)), 1218 + created: now 1219 + }); 1220 + } 1221 + } 1222 + } 1223 + } 1224 + 1225 + // For each column 1226 + for (let i = 0; i < columns; i++) { 1227 + // Calculate current position of this vine 1228 + const x = i * fontSize * 1.5; // Space vines further apart 1229 + 1230 + // For each character in this column 1231 + for (let j = 0; j < Math.ceil(drops[i] / fontSize); j++) { 1232 + const y = j * fontSize; 1233 + 1234 + // Skip rendering some characters to create gaps in vines 1235 + if (Math.random() < 0.05 && j > 3) continue; 1236 + 1237 + // Calculate age of this character 1238 + const charAge = now - lastCharChangeTime[i][j]; 1239 + 1240 + // Randomly change some characters over time - slower rate for natural movement 1241 + if (j === 0 && (Math.random() < 0.005 || charAge > 8000)) { 1242 + // Top character might change between leaves/flowers 1243 + if (columnTypes[i] === 'leaf' || Math.random() < 0.6) { 1244 + currentChars[i][j] = leafChars.charAt(Math.floor(Math.random() * leafChars.length)); 1245 + } else { 1246 + currentChars[i][j] = vineChars.charAt(Math.floor(Math.random() * vineChars.length)); 1247 + } 1248 + lastCharChangeTime[i][j] = now; 1249 + } else if (j > 0 && Math.random() < 0.001) { 1250 + // Occasionally grow new leaves along the vine 1251 + if (Math.random() < 0.2) { 1252 + currentChars[i][j] = leafChars.charAt(Math.floor(Math.random() * leafChars.length)); 1253 + } else { 1254 + const vineIndex = Math.min(vineThickness[i] * 3, vineChars.length - 1); 1255 + currentChars[i][j] = vineChars.charAt(Math.floor(Math.random() * vineIndex)); 1256 + } 1257 + lastCharChangeTime[i][j] = now; 1258 + } 1259 + 1260 + // Calculate distance from head of the vine 1261 + const distanceFromHead = (drops[i] - y); 1262 + 1263 + // Determine color based on position and type 1264 + if (j === 0 && (currentChars[i][j] === '❀' || currentChars[i][j] === '✿' || 1265 + currentChars[i][j] === '❁' || currentChars[i][j] === '✾')) { 1266 + // Flowers are more colorful - pinkish 1267 + ctx.fillStyle = 'rgba(255, 180, 220, 0.9)'; 1268 + ctx.shadowColor = 'rgba(255, 150, 200, 0.6)'; 1269 + ctx.shadowBlur = 5; 1270 + } else if (currentChars[i][j] === '☘' || leafChars.includes(currentChars[i][j])) { 1271 + // Leaf characters are brightest with different green 1272 + ctx.fillStyle = 'rgba(120, 255, 150, 0.9)'; 1273 + ctx.shadowColor = 'rgba(77, 250, 123, 0.5)'; 1274 + ctx.shadowBlur = 3; 1275 + } else if (distanceFromHead < fontSize) { 1276 + // Growing tip of vine is brightest 1277 + ctx.fillStyle = 'rgba(120, 255, 150, 0.9)'; 1278 + ctx.shadowColor = 'rgba(77, 250, 123, 0.5)'; 1279 + ctx.shadowBlur = 5; 1280 + } else if (distanceFromHead < fontSize * 8) { 1281 + // Newer part of vine is brighter 1282 + const opacity = 0.8 - (distanceFromHead / (fontSize * 10)); 1283 + ctx.fillStyle = `rgba(77, 180, 100, ${opacity.toFixed(2)})`; 1284 + ctx.shadowColor = 'transparent'; 1285 + ctx.shadowBlur = 0; 1286 + } else { 1287 + // Older parts of vine are darker 1288 + const opacity = Math.max(0, 0.4 - (distanceFromHead / (canvas.height * 2))); 1289 + // Darker green for older vines 1290 + ctx.fillStyle = `rgba(40, 120, 60, ${opacity.toFixed(2)})`; 1291 + ctx.shadowColor = 'transparent'; 1292 + ctx.shadowBlur = 0; 1293 + } 1294 + 1295 + // Add slight random swaying to vines 1296 + const swayAmount = Math.sin((now / 2000) + i) * 2; // Gentle swaying effect 1297 + const adjustedX = x + swayAmount; 1298 + 1299 + // Draw the character 1300 + if (y < canvas.height) { 1301 + // Adjust size for special characters 1302 + if (leafChars.includes(currentChars[i][j])) { 1303 + ctx.font = `${fontSize * 1.2}px 'JetBrains Mono', monospace`; 1304 + ctx.fillText(currentChars[i][j], adjustedX, y); 1305 + ctx.font = `${fontSize}px 'JetBrains Mono', monospace`; // Reset font 1306 + } else { 1307 + ctx.fillText(currentChars[i][j], adjustedX, y); 1308 + } 1309 + } 1310 + } 1311 + 1312 + // Move the vine down - slower for natural growth 1313 + drops[i] += fontSize * (0.02 + Math.random() * 0.03); 1314 + 1315 + // Reset vine when it reaches bottom or randomly (much less frequent) 1316 + if (drops[i] > canvas.height * 2 || (Math.random() < 0.0005 && drops[i] > canvas.height * 0.6)) { 1317 + drops[i] = Math.random() * -30; 1318 + // Maybe change vine type 1319 + if (Math.random() < 0.3) { 1320 + columnTypes[i] = Math.random() < 0.7 ? 'vine' : 'leaf'; 1321 + vineThickness[i] = Math.floor(Math.random() * 3) + 1; 1322 + } 1323 + } 1324 + } 1325 + 1326 + // Draw cross connections between vines 1327 + crossConnections.forEach((connection, index) => { 1328 + const sourceX = connection.source * fontSize * 1.5; 1329 + const targetX = connection.target * fontSize * 1.5; 1330 + const y = connection.height; 1331 + const heightIndex = Math.floor(y / fontSize); 1332 + 1333 + // Calculate a safe display Y - make sure it's within the grown vines 1334 + const safeY = Math.min( 1335 + Math.min(drops[connection.source], drops[connection.target]), 1336 + connection.height 1337 + ); 1338 + 1339 + // Convert to display coords 1340 + const displayY = Math.floor(safeY / fontSize) * fontSize; 1341 + 1342 + // Only draw if connection is within visible area 1343 + if (displayY < 0 || displayY > canvas.height) return; 1344 + 1345 + // Connection age effect 1346 + const age = now - connection.created; 1347 + const maxAge = 20000; // 20 seconds lifetime for connections 1348 + 1349 + // Remove old connections 1350 + if (age > maxAge) { 1351 + crossConnections.splice(index, 1); 1352 + return; 1353 + } 1354 + 1355 + // Fade in/out effect 1356 + let opacity = 1.0; 1357 + if (age < 1000) { 1358 + // Fade in 1359 + opacity = age / 1000; 1360 + } else if (age > maxAge - 2000) { 1361 + // Fade out 1362 + opacity = (maxAge - age) / 2000; 1363 + } 1364 + 1365 + // Draw connection 1366 + const connectionWidth = Math.abs(targetX - sourceX); 1367 + const steps = Math.ceil(connectionWidth / (fontSize * 0.8)); 1368 + 1369 + // Lighter green for branches 1370 + ctx.fillStyle = `rgba(120, 255, 150, ${opacity.toFixed(2)})`; 1371 + ctx.shadowColor = 'rgba(77, 250, 123, 0.4)'; 1372 + ctx.shadowBlur = 2; 1373 + 1374 + // Draw branch character at each step 1375 + let branchChar; 1376 + 1377 + if (sourceX < targetX) { 1378 + // Left to right 1379 + branchChar = '─'; 1380 + } else { 1381 + // Right to left 1382 + branchChar = '─'; 1383 + } 1384 + 1385 + for (let s = 0; s <= steps; s++) { 1386 + // Calculate position 1387 + const progress = s / steps; 1388 + const stepX = sourceX + (targetX - sourceX) * progress; 1389 + const wiggle = Math.sin(progress * Math.PI) * 5; 1390 + 1391 + // Choose appropriate connection character 1392 + let connChar = branchChar; 1393 + 1394 + // Special characters for start, middle and end 1395 + if (s === 0) { 1396 + connChar = '├'; 1397 + } else if (s === steps) { 1398 + connChar = '┤'; 1399 + } else if (s === Math.floor(steps/2)) { 1400 + // Add a leaf or flower in the middle sometimes 1401 + if (Math.random() < 0.3) { 1402 + connChar = leafChars.charAt(Math.floor(Math.random() * leafChars.length)); 1403 + } else { 1404 + connChar = s % 2 === 0 ? '┼' : '┴'; 1405 + } 1406 + } else { 1407 + // Occasional decorative elements 1408 + if (Math.random() < 0.1) { 1409 + connChar = '·'; 1410 + } 1411 + } 1412 + 1413 + ctx.fillText(connChar, stepX, displayY + wiggle); 1414 + } 1415 + }); 1416 + 1417 + // Schedule next frame 1418 + requestAnimationFrame(drawVineEffect); 1419 + } 1420 + 1421 + // Start the animation 1422 + drawVineEffect(); 992 1423 // Add hover event listeners after DOM content is loaded 993 1424 function setupHoverEffects() { 994 1425 // Keep track of the currently active item ··· 996 1427 997 1428 document.querySelectorAll('.feed-item').forEach(item => { 998 1429 item.addEventListener('mouseenter', () => { 999 - // Close all sections in previously hovered item 1000 - if (currentHoveredItem && currentHoveredItem !== item) { 1001 - // Remove this section - we no longer show the full content 1002 - 1003 - // No need to close preview content now since it's controlled by CSS hover 1004 - 1005 - // References are now controlled by CSS hover 1006 - } 1007 - 1008 1430 // Set this as current hovered item 1009 1431 currentHoveredItem = item; 1010 - 1011 - // Remove this section - we no longer show the full content 1432 + }); 1433 + 1434 + // Track mouse position for the ripple effect 1435 + item.addEventListener('mousemove', (e) => { 1436 + // Get position relative to the element 1437 + const rect = item.getBoundingClientRect(); 1438 + const x = ((e.clientX - rect.left) / rect.width) * 100; 1439 + const y = ((e.clientY - rect.top) / rect.height) * 100; 1012 1440 1013 - // Preview content is shown automatically by CSS on hover 1441 + // Set custom properties for the radial gradient 1442 + item.style.setProperty('--mouse-x', `${x}%`); 1443 + item.style.setProperty('--mouse-y', `${y}%`); 1014 1444 }); 1015 1445 }); 1016 1446 } ··· 1356 1786 entriesHTML += ` 1357 1787 <article id="${entry.articleId}" class="feed-item" ${dateAttr}> 1358 1788 <div class="feed-item-row"> 1359 - <div class="feed-item-date">${monthNames[month]} ${getDayWithOrdinal(date)}, ${year}</div> 1789 + <div class="feed-item-date">${getDayWithOrdinal(date)} ${shortMonthNames[month]} ${year}</div> 1360 1790 <div class="feed-item-author">${entry.author}</div> 1361 1791 <div class="feed-item-content-wrapper"> 1362 1792 <div class="feed-item-title"><a href="${entry.link}" target="_blank">${entry.title}</a></div><div class="feed-item-preview">${entry.contentHtml}</div> ··· 1649 2079 } 1650 2080 } 1651 2081 1652 - // Set up hover effects 2082 + // Set up hover effects and ripple animations 1653 2083 setupHoverEffects(); 1654 2084 2085 + // Create a ripple effect that travels across the content area 2086 + const feedContainer = document.querySelector('.feed-container'); 2087 + feedContainer.addEventListener('mousemove', (e) => { 2088 + // Ripple between items as mouse moves 2089 + const items = document.querySelectorAll('.feed-item, .link-item'); 2090 + items.forEach(item => { 2091 + const rect = item.getBoundingClientRect(); 2092 + const centerX = rect.left + rect.width / 2; 2093 + const centerY = rect.top + rect.height / 2; 2094 + 2095 + // Calculate distance from mouse to center of item 2096 + const dx = e.clientX - centerX; 2097 + const dy = e.clientY - centerY; 2098 + const distance = Math.sqrt(dx * dx + dy * dy); 2099 + 2100 + // Calculate fade based on distance 2101 + const maxDistance = 400; // max distance for effect 2102 + const intensity = Math.max(0, 1 - (distance / maxDistance)); 2103 + 2104 + if (intensity > 0.05) { 2105 + // Extremely subtle glow - minimized for optimal text readability 2106 + item.style.boxShadow = `0 0 ${intensity * 8}px var(--hover-glow)`; 2107 + item.style.transform = `scale(${1 + intensity * 0.005})`; 2108 + item.style.transition = 'box-shadow 0.4s ease-out, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1)'; 2109 + } else { 2110 + item.style.boxShadow = 'none'; 2111 + item.style.transform = 'scale(1)'; 2112 + } 2113 + }); 2114 + }); 2115 + 2116 + // Add hover tracking for link items too 2117 + document.querySelectorAll('.link-item').forEach(item => { 2118 + item.addEventListener('mousemove', (e) => { 2119 + // Get position relative to the element 2120 + const rect = item.getBoundingClientRect(); 2121 + const x = ((e.clientX - rect.left) / rect.width) * 100; 2122 + const y = ((e.clientY - rect.top) / rect.height) * 100; 2123 + 2124 + // Set custom properties for the radial gradient 2125 + item.style.setProperty('--mouse-x', `${x}%`); 2126 + item.style.setProperty('--mouse-y', `${y}%`); 2127 + }); 2128 + }); 2129 + 1655 2130 // Process all external links from entries 1656 2131 const linksContainer = document.getElementById('link-items'); 1657 2132 const allExternalLinks = []; ··· 1836 2311 // Create link item HTML 1837 2312 linksHTML += ` 1838 2313 <div class="link-item" data-year="${date.getFullYear()}" data-month="${date.getMonth()}"> 1839 - <div class="link-item-date">${monthNames[date.getMonth()]} ${getLinkDayWithOrdinal(date)}, ${date.getFullYear()}</div> 2314 + <div class="link-item-date">${getLinkDayWithOrdinal(date)} ${shortMonthNames[date.getMonth()]} ${date.getFullYear()}</div> 1840 2315 <div class="link-item-source" title="From: ${link.sourceTitle}"> 1841 2316 <a href="${link.sourceLink}" target="_blank" style="color: inherit; text-decoration: none;"> 1842 2317 ${link.source}