madebydanny.uk written in html, css, and a lot of JavaScript I don't understand madebydanny.uk
html css javascript
1
fork

Configure Feed

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

new update thing

+370 -1616
.DS_Store

This is a binary file and will not be displayed.

+3 -3
cdn.html cdn/index.html
··· 16 16 <!-- Fonts & Styles --> 17 17 <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;600&display=swap" rel="stylesheet"> 18 18 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" /> 19 - <link rel="stylesheet" href="css/cdn.css"> 19 + <link rel="stylesheet" href="/css/cdn.css"> 20 20 21 21 <link rel="icon" type="image/png" href="https://public-cdn.madebydanny.uk/user-content/2025-09-13/20-45-17_database-solid-full.svg" /> 22 - <script src="js/cdn-v2.js" defer></script> 22 + <script src="/js/cdn-v2.js" defer></script> 23 23 </head> 24 24 <body> 25 25 <header2> 26 26 <h1><i class="fa-solid fa-database"></i> MBD CDN <i>2.0</i></h1> 27 27 <nav> 28 28 <a href="/index.html">Home</a> 29 - <a href="/docs.html">Docs</a> 29 + <a href="docs.html">Docs</a> 30 30 </nav> 31 31 </header2> 32 32 <header class="center">
-939
css/index.css
··· 1 - body { 2 - background-color: white; 3 - color: white; 4 - /* Desktop wallpaper */ 5 - background-image: url("https://imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/site-assets/com.atproto.sync.png"); 6 - background-position: center center; 7 - background-size: cover; 8 - background-attachment: fixed; 9 - font-family: "Itim", cursive; 10 - font-weight: 400; 11 - font-style: normal; 12 - margin: 0; 13 - padding: 20px 0; 14 - line-height: 1.6; 15 - } 16 - 17 - /* Main content container with improved contrast */ 18 - .center { 19 - margin: auto; 20 - width: 90%; 21 - max-width: 1200px; 22 - } 23 - 24 - /* Section title styling */ 25 - .section-title { 26 - color: #ffffff; 27 - font-size: 1.4em; 28 - margin: 0 0 15px 0; 29 - font-weight: 600; 30 - } 31 - 32 - /* Top section layout */ 33 - .top-section { 34 - display: grid; 35 - grid-template-columns: 1fr 1fr; 36 - gap: 20px; 37 - margin-bottom: 20px; 38 - } 39 - 40 - /* White card styling */ 41 - .white-card { 42 - backdrop-filter: blur(20px); 43 - background: #79f7a394; 44 - border-radius: 16px; 45 - padding: 30px; 46 - margin: 20px 0; 47 - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 48 - 0 0 0 1px rgba(255, 255, 255, 0.1) inset; 49 - transition: transform 0.3s ease, box-shadow 0.3s ease; 50 - color: white; 51 - } 52 - 53 - .white-card:hover { 54 - transform: translateY(-4px); 55 - box-shadow: 0 12px 48px rgba(0, 0, 0, 0.4), 56 - 0 0 0 1px rgba(255, 255, 255, 0.2) inset; 57 - } 58 - 59 - /* Main content container with improved contrast */ 60 - .center { 61 - margin: auto; 62 - width: 65%; 63 - max-width: 900px; 64 - 65 - } 66 - 67 - /* Navigation with better contrast */ 68 - nav ul { 69 - list-style-type: none; 70 - margin: 0; 71 - padding: 0; 72 - display: flex; 73 - flex-wrap: wrap; 74 - justify-content: center; 75 - gap: 10px; 76 - } 77 - nav ul li { 78 - padding: 0; 79 - } 80 - nav ul li a { 81 - display: block; 82 - color: #ffffff; 83 - text-align: center; 84 - padding: 12px 18px; 85 - text-decoration: none; 86 - border-radius: 6px; 87 - background-color: rgba(175, 64, 175, 0.54); 88 - border: 1px solid rgba(175, 64, 175, 0.54); 89 - transition: all 0.3s ease; 90 - font-weight: 500; 91 - } 92 - nav ul li a:hover { 93 - color: #ffffff; 94 - background-color: rgba(175, 64, 175, 0.54); 95 - border-color: #9999ff; 96 - transform: translateY(-2px); 97 - } 98 - 99 - /* Links with better visibility */ 100 - a { 101 - color: #79F7A4; 102 - text-decoration: none; 103 - transition: color 0.2s ease; 104 - } 105 - a:hover { 106 - color: white; 107 - text-decoration: underline; 108 - } 109 - 110 - hr { 111 - background: linear-gradient(to right, transparent, #9999ff, transparent); 112 - border: none; 113 - height: 2px; 114 - margin: 30px 0; 115 - } 116 - 117 - /* Headings with better contrast */ 118 - h3 { 119 - color: #ffffff; 120 - font-size: 1.4em; 121 - margin-top: 20px; 122 - margin-bottom: 15px; 123 - font-weight: 600; 124 - } 125 - 126 - /* Scroll to top button */ 127 - #myBtn { 128 - display: none; 129 - position: fixed; 130 - bottom: 20px; 131 - right: 30px; 132 - z-index: 99; 133 - font-size: 18px; 134 - border: none; 135 - outline: none; 136 - background-color: #2F7D61; 137 - color: white; 138 - cursor: pointer; 139 - padding: 15px; 140 - border-radius: 8px; 141 - transition: all 0.3s ease; 142 - } 143 - #myBtn:hover { 144 - background-color: #5CFFC5; 145 - transform: translateY(-2px); 146 - } 147 - 148 - /* Bluesky Profile Header with better contrast */ 149 - .bsky-profile-header { 150 - margin: 20px 0; 151 - border-radius: 16px; 152 - overflow: hidden; 153 - backdrop-filter: blur(20px); 154 - border: 1px solid rgba(153, 153, 255, 0.2); 155 - box-sizing: border-box; 156 - background: #79F7A494; 157 - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 158 - 0 0 0 1px rgba(255, 255, 255, 0.1) inset; 159 - transition: all 0.3s ease; 160 - } 161 - 162 - .bsky-profile-header:hover { 163 - transform: translateY(-4px); 164 - box-shadow: 0 12px 48px rgba(0, 0, 0, 0.4), 165 - 0 0 0 1px rgba(255, 255, 255, 0.2) inset; 166 - } 167 - #banner { 168 - width: 100%; 169 - height: 200px; 170 - object-fit: cover; 171 - display: none; 172 - } 173 - .bsky-header-content { 174 - padding: 25px; 175 - position: relative; 176 - } 177 - #pfp { 178 - width: 120px; 179 - height: 120px; 180 - border-radius: 50%; 181 - object-fit: cover; 182 - display: none; 183 - margin: -60px 0 15px 0; 184 - border: 4px solid #2F7D61; 185 - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6), 186 - 0 0 0 2px rgba(255, 255, 255, 0.1); 187 - transition: transform 0.3s ease, box-shadow 0.3s ease; 188 - } 189 - #pfp:hover { 190 - transform: scale(1.05); 191 - } 192 - .bsky-info { 193 - margin-top: 10px; 194 - } 195 - #user { 196 - font-size: 28px; 197 - font-weight: bold; 198 - margin-bottom: 5px; 199 - color: white; 200 - } 201 - #handle { 202 - font-size: 16px; 203 - color: white; 204 - margin-bottom: 15px; 205 - } 206 - #bio { 207 - color: white; 208 - line-height: 1.7; 209 - white-space: pre-wrap; 210 - margin-bottom: 15px; 211 - font-size: 15px; 212 - } 213 - #stats { 214 - display: flex; 215 - gap: 25px; 216 - font-size: 14px; 217 - color: white; 218 - } 219 - #stats span { 220 - color: white; 221 - font-weight: bold; 222 - } 223 - .bsky-loading { 224 - text-align: center; 225 - color: #ffffff; 226 - padding: 40px 20px; 227 - } 228 - 229 - .bsky-button { 230 - display: inline-block; 231 - padding: 12px 24px; 232 - background-color: #2F7D61; 233 - color: white; 234 - text-decoration: none; 235 - border-radius: 8px; 236 - font-weight: bold; 237 - transition: all 0.3s ease; 238 - margin-top: 10px; 239 - } 240 - .bsky-button:hover { 241 - background-color: #79F7A4; 242 - transform: translateY(-2px); 243 - color: #2F7D61; 244 - } 245 - 246 - /* Latest Bluesky Post with better contrast */ 247 - #latest-bsky-post { 248 - backdrop-filter: blur(20px); 249 - background: #79f7a394; 250 - border-radius: 16px; 251 - padding: 30px; 252 - margin: 20px 0; 253 - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 254 - 0 0 0 1px rgba(255, 255, 255, 0.1) inset; 255 - border: 1px solid rgba(153, 153, 255, 0.2); 256 - transition: all 0.3s ease; 257 - } 258 - 259 - #latest-bsky-post:hover { 260 - transform: translateY(-4px); 261 - box-shadow: 0 12px 48px rgba(0, 0, 0, 0.4), 262 - 0 0 0 1px rgba(255, 255, 255, 0.2) inset; 263 - } 264 - 265 - .post-header { 266 - display: flex; 267 - align-items: center; 268 - gap: 12px; 269 - margin-bottom: 15px; 270 - } 271 - 272 - .post-avatar { 273 - width: 48px; 274 - height: 48px; 275 - border-radius: 50%; 276 - border: 2px solid #2F7D61; 277 - } 278 - 279 - .post-user-info { 280 - flex: 1; 281 - } 282 - 283 - .post-display-name { 284 - font-weight: bold; 285 - color: white; 286 - font-size: 16px; 287 - cursor: pointer; 288 - transition: color 0.2s ease; 289 - } 290 - 291 - .post-display-name:hover { 292 - color: white; 293 - } 294 - 295 - .post-handle { 296 - color: white; 297 - font-size: 14px; 298 - cursor: pointer; 299 - transition: color 0.2s ease; 300 - } 301 - 302 - .post-handle:hover { 303 - color: white; 304 - text-decoration: underline; 305 - } 306 - 307 - .post-timestamp { 308 - color: white; 309 - font-size: 13px; 310 - } 311 - 312 - .post-text { 313 - color: white; 314 - line-height: 1.7; 315 - margin-bottom: 15px; 316 - white-space: pre-wrap; 317 - font-size: 15px; 318 - word-wrap: break-word; 319 - } 320 - 321 - .post-text a { 322 - color: white; 323 - text-decoration: none; 324 - transition: color 0.2s ease; 325 - } 326 - 327 - .post-text a:hover { 328 - color: #d4d4ff; 329 - text-decoration: underline; 330 - } 331 - 332 - .post-embed { 333 - margin-top: 15px; 334 - border-radius: 8px; 335 - overflow: hidden; 336 - } 337 - 338 - .post-embed img { 339 - width: 100%; 340 - max-width: 350px; 341 - display: block; 342 - border-radius: 8px; 343 - } 344 - 345 - .post-embed-external img { 346 - width: 60px; 347 - height: 60px; 348 - object-fit: cover; 349 - border-radius: 4px; 350 - } 351 - 352 - .post-embed-external { 353 - background-color: rgba(0, 0, 0, 0.5); 354 - padding: 15px; 355 - display: flex; 356 - gap: 12px; 357 - align-items: center; 358 - border: 1px solid rgba(153, 153, 255, 0.2); 359 - border-radius: 8px; 360 - cursor: pointer; 361 - transition: all 0.3s ease; 362 - text-decoration: none; 363 - color: inherit; 364 - } 365 - 366 - .post-embed-external:hover { 367 - background-color: rgba(0, 0, 0, 0.7); 368 - border-color: rgba(153, 153, 255, 0.5); 369 - transform: translateY(-2px); 370 - } 371 - 372 - .post-embed-text { 373 - flex: 1; 374 - } 375 - 376 - .post-embed-title { 377 - color: #ffffff; 378 - font-weight: bold; 379 - margin-bottom: 4px; 380 - } 381 - 382 - .post-embed-description { 383 - color: #d0d0d0; 384 - font-size: 13px; 385 - line-height: 1.4; 386 - } 387 - 388 - .post-embed-url { 389 - color: white; 390 - font-size: 12px; 391 - } 392 - 393 - .post-stats { 394 - display: flex; 395 - gap: 25px; 396 - margin-top: 15px; 397 - padding-top: 15px; 398 - font-size: 14px; 399 - color: #d0d0d0; 400 - } 401 - 402 - .post-stats i { 403 - margin-right: 6px; 404 - color: white; 405 - } 406 - 407 - .post-stats div { 408 - color:white; 409 - } 410 - 411 - .view-post-link { 412 - display: inline-block; 413 - margin-top: 12px; 414 - color: white; 415 - text-decoration: none; 416 - font-size: 14px; 417 - font-weight: 500; 418 - } 419 - 420 - .view-post-link:hover { 421 - color: white; 422 - text-decoration: underline; 423 - } 424 - 425 - /* Projects list styling */ 426 - ul { 427 - padding-left: 20px; 428 - } 429 - 430 - ul li { 431 - margin-bottom: 12px; 432 - color: #e6e6e6; 433 - } 434 - 435 - ul li i { 436 - color: #cccccc; 437 - } 438 - 439 - /* Footer styling */ 440 - .center > p:last-of-type { 441 - color: #cccccc; 442 - font-size: 14px; 443 - margin-top: 20px; 444 - } 445 - 446 - /* Responsive design */ 447 - /* Content sections styling */ 448 - .content-section { 449 - margin-bottom: 30px; 450 - } 451 - 452 - /* About section styling */ 453 - #about { 454 - color: #ffffff; 455 - font-size: 16px; 456 - line-height: 1.8; 457 - } 458 - 459 - #about p { 460 - margin: 0 0 15px 0; 461 - } 462 - 463 - #about p:last-child { 464 - margin-bottom: 0; 465 - } 466 - 467 - .about-loading { 468 - text-align: center; 469 - color: #ffffff; 470 - padding: 20px; 471 - } 472 - 473 - 474 - 475 - @media (max-width: 1200px) { 476 - .center { 477 - width: 95%; 478 - } 479 - } 480 - 481 - @media (max-width: 900px) { 482 - .top-section { 483 - grid-template-columns: 1fr; 484 - } 485 - 486 - .bsky-profile-header, 487 - #latest-bsky-post, 488 - .content-section { 489 - margin-bottom: 20px; 490 - } 491 - 492 - } 493 - 494 - @media (max-width: 600px) { 495 - body { 496 - background-attachment: scroll; 497 - padding: 10px; 498 - } 499 - .center { 500 - width: 100%; 501 - padding: 10px; 502 - } 503 - nav ul { 504 - flex-direction: column; 505 - align-items: center; 506 - } 507 - nav ul li a { 508 - width: 100%; 509 - padding: 12px; 510 - } 511 - .section-title { 512 - font-size: 1.3em; 513 - text-align: center; 514 - } 515 - #myBtn { 516 - right: 15px; 517 - bottom: 15px; 518 - padding: 12px; 519 - font-size: 16px; 520 - } 521 - .white-card { 522 - padding: 15px; 523 - } 524 - } 525 - #banner { 526 - height: 120px; 527 - } 528 - #pfp { 529 - width: 80px; 530 - height: 80px; 531 - margin: -40px 0 10px 0; 532 - border: 3px solid #2F7D61; 533 - } 534 - #user { 535 - font-size: 22px; 536 - } 537 - #handle { 538 - font-size: 14px; 539 - } 540 - #bio { 541 - font-size: 14px; 542 - } 543 - #stats { 544 - font-size: 13px; 545 - flex-wrap: wrap; 546 - gap: 15px; 547 - } 548 - /* Photo Gallery */ 549 - #simple-photo-gallery { 550 - text-align: center; 551 - margin: 20px 0; 552 - backdrop-filter: blur(20px); 553 - background: #79f7a396; 554 - border-radius: 16px; 555 - padding: 30px; 556 - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 557 - 0 0 0 1px rgba(255, 255, 255, 0.1) inset; 558 - border: 1px solid rgba(153, 153, 255, 0.2); 559 - transition: all 0.3s ease; 560 - } 561 - 562 - #simple-photo-gallery:hover { 563 - transform: translateY(-4px); 564 - box-shadow: 0 12px 48px rgba(0, 0, 0, 0.4), 565 - 0 0 0 1px rgba(255, 255, 255, 0.2) inset; 566 - } 567 - 568 - #simple-photo-gallery h2 { 569 - font-size: 1.6em; 570 - font-weight: 700; 571 - margin-bottom: 20px; 572 - color: white; 573 - display: flex; 574 - align-items: left; 575 - justify-content: left; 576 - gap: 12px; 577 - } 578 - 579 - #simple-photo-gallery h2 i { 580 - color: white; 581 - } 582 - 583 - .gallery { 584 - display: grid; 585 - grid-template-columns: repeat(4, 1fr); /* 4 columns on desktop */ 586 - gap: 16px; 587 - margin: 20px 0; 588 - } 589 - 590 - .gallery-item { 591 - width: 100%; 592 - aspect-ratio: 1; 593 - object-fit: cover; 594 - border-radius: 12px; 595 - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); 596 - border: 2px solid rgba(255, 255, 255, 0.1); 597 - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); 598 - cursor: pointer; 599 - } 600 - 601 - .gallery-item:hover { 602 - transform: scale(1.08) rotate(2deg); 603 - box-shadow: #2F7D61; 604 - border-color: white; 605 - z-index: 10; 606 - } 607 - 608 - .btn { 609 - padding: 12px 28px; 610 - background: linear-gradient(135deg, #9999ff, #b3b3ff); 611 - color: white; 612 - border: none; 613 - border-radius: 10px; 614 - cursor: pointer; 615 - transition: all 0.3s ease; 616 - font-weight: 600; 617 - font-size: 15px; 618 - box-shadow: 0 4px 16px rgba(153, 153, 255, 0.3); 619 - position: relative; 620 - overflow: hidden; 621 - } 622 - 623 - .btn::before { 624 - content: ''; 625 - position: absolute; 626 - top: 0; 627 - left: -100%; 628 - width: 100%; 629 - height: 100%; 630 - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); 631 - transition: left 0.5s ease; 632 - } 633 - 634 - .btn:hover { 635 - background: linear-gradient(135deg, #b3b3ff, #d4d4ff); 636 - transform: translateY(-2px); 637 - box-shadow: 0 8px 24px rgba(153, 153, 255, 0.5); 638 - } 639 - 640 - .btn:hover::before { 641 - left: 100%; 642 - } 643 - 644 - .btn a { 645 - color: white; 646 - text-decoration: none; 647 - } 648 - 649 - #footer { 650 - margin-top: 20px; 651 - font-size: 14px; 652 - text-align: center; 653 - } 654 - 655 - /* Current Status Card */ 656 - #current-status { 657 - background: #79F7A4; 658 - border: 2px solid #5CFFC9; 659 - border-radius: 16px; 660 - padding: 20px; 661 - margin-bottom: 20px; 662 - text-align: center; 663 - backdrop-filter: blur(20px); 664 - box-shadow:#2F7D61; 665 - position: relative; 666 - overflow: hidden; 667 - } 668 - 669 - #current-status::before { 670 - content: ''; 671 - position: absolute; 672 - top: -50%; 673 - left: -50%; 674 - width: 200%; 675 - height: 200%; 676 - background: linear-gradient(45deg, transparent, rgba(153, 153, 255, 0.1), transparent); 677 - animation: statusShine 3s infinite; 678 - } 679 - 680 - @keyframes statusShine { 681 - 0% { transform: translate(-50%, -50%) rotate(0deg); } 682 - 100% { transform: translate(-50%, -50%) rotate(360deg); } 683 - } 684 - 685 - #current-status:hover { 686 - transform: scale(1.02); 687 - border-color: #2F7D61; 688 - } 689 - 690 - #current-status b { 691 - color: #2F7D61; 692 - font-size: 1.1em; 693 - position: relative; 694 - z-index: 1; 695 - } 696 - 697 - /* Modern Projects & Tangled Repos Styling */ 698 - .project-item, .tangled-item { 699 - background: linear-gradient(135deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.2)); 700 - border-radius: 12px; 701 - padding: 20px; 702 - margin-bottom: 16px; 703 - border: 1px solid rgba(255, 255, 255, 0.1); 704 - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 705 - position: relative; 706 - overflow: hidden; 707 - } 708 - 709 - .project-item::before, .tangled-item::before { 710 - content: ''; 711 - position: absolute; 712 - top: 0; 713 - left: 0; 714 - width: 4px; 715 - height: 100%; 716 - background: linear-gradient(180deg, #5CFFC5, #5CFFC5); 717 - opacity: 0; 718 - transition: opacity 0.3s ease; 719 - } 720 - 721 - .project-item:hover, .tangled-item:hover { 722 - transform: translateX(8px); 723 - border-color: #79F7A4; 724 - background: linear-gradient(135deg, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.3)); 725 - box-shadow: 0 8px 24px rgba(153, 153, 255, 0.15); 726 - } 727 - 728 - .project-item:hover::before, .tangled-item:hover::before { 729 - opacity: 1; 730 - } 731 - 732 - .project-item h3, .tangled-item h3 { 733 - margin-top: 0; 734 - margin-bottom: 12px; 735 - font-size: 1.3em; 736 - font-weight: 600; 737 - color: #ffffff; 738 - display: flex; 739 - align-items: center; 740 - gap: 10px; 741 - } 742 - 743 - .project-item h3 a, .tangled-item h3 a { 744 - color: #ffffff; 745 - text-decoration: none; 746 - transition: color 0.3s ease; 747 - display: inline-flex; 748 - align-items: center; 749 - gap: 8px; 750 - } 751 - 752 - .project-item h3 a:hover, .tangled-item h3 a:hover { 753 - color: white; 754 - } 755 - 756 - .project-item h3 a::after, .tangled-item h3 a::after { 757 - content: '→'; 758 - opacity: 0; 759 - transform: translateX(-10px); 760 - transition: all 0.3s ease; 761 - } 762 - 763 - .project-item:hover h3 a::after, .tangled-item:hover h3 a::after { 764 - opacity: 1; 765 - transform: translateX(0); 766 - } 767 - 768 - .project-item p, .tangled-item p { 769 - margin: 8px 0; 770 - color: #d0d0d0; 771 - line-height: 1.6; 772 - font-size: 0.95em; 773 - } 774 - 775 - .project-item p strong, .tangled-item p strong { 776 - color: white; 777 - font-weight: 600; 778 - } 779 - 780 - /* Tangled repo specific styling */ 781 - .tangled-item .fa-server { 782 - color: white; 783 - } 784 - 785 - .tangled-item .fa-clock { 786 - color: white; 787 - margin-right: 6px; 788 - } 789 - 790 - /* Section headers with icons */ 791 - #projects h2, #tangled-repo h2, #leaflets h2, #thanks h2 { 792 - font-size: 1.6em; 793 - font-weight: 700; 794 - margin-bottom: 20px; 795 - color: white; 796 - display: flex; 797 - align-items: center; 798 - gap: 12px; 799 - padding-bottom: 12px; 800 - border-bottom: 2px solid white; 801 - } 802 - 803 - #projects h2 i, #tangled-repo h2 i, #leaflets h2 i, #thanks h2 i { 804 - color: white; 805 - font-size: 0.9em; 806 - } 807 - 808 - /* Leaflets RSS Feed Styling */ 809 - #leaflets #rss .leaflet-item, 810 - #rss .feedItem { 811 - background: linear-gradient(135deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.2)); 812 - border-radius: 12px; 813 - padding: 20px; 814 - margin-bottom: 16px; 815 - border: 1px solid rgba(255, 255, 255, 0.1); 816 - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 817 - position: relative; 818 - overflow: hidden; 819 - } 820 - 821 - #leaflets #rss .leaflet-item::before, 822 - #rss .feedItem::before { 823 - content: ''; 824 - position: absolute; 825 - top: 0; 826 - left: 0; 827 - width: 4px; 828 - height: 100%; 829 - background: linear-gradient(180deg, #9999ff, #b3b3ff); 830 - opacity: 0; 831 - transition: opacity 0.3s ease; 832 - } 833 - 834 - #leaflets #rss .leaflet-item:hover, 835 - #rss .feedItem:hover { 836 - transform: translateX(8px); 837 - border-color: #2F7D61; 838 - background: linear-gradient(135deg, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.3)); 839 - box-shadow: 0 8px 24px rgba(153, 153, 255, 0.15); 840 - } 841 - 842 - #leaflets #rss .leaflet-item:hover::before, 843 - #rss .feedItem:hover::before { 844 - opacity: 1; 845 - } 846 - 847 - #leaflets #rss h3, 848 - #rss .feedItem h3, 849 - #rss .feedItem .feedTitle { 850 - margin-top: 0; 851 - margin-bottom: 12px; 852 - font-size: 1.3em; 853 - font-weight: 600; 854 - color: #ffffff; 855 - } 856 - 857 - #leaflets #rss a, 858 - #rss .feedItem a { 859 - color: white; 860 - text-decoration: none; 861 - transition: color 0.3s ease; 862 - display: inline-flex; 863 - align-items: center; 864 - gap: 8px; 865 - } 866 - 867 - #leaflets #rss a:hover, 868 - #rss .feedItem a:hover { 869 - color: #2F7D61; 870 - } 871 - 872 - #leaflets #rss .leaflet-description, 873 - #rss .feedItem .feedDescription, 874 - #rss .feedItem p { 875 - margin: 8px 0; 876 - color: #d0d0d0; 877 - line-height: 1.6; 878 - font-size: 0.95em; 879 - } 880 - 881 - #leaflets #rss .leaflet-date, 882 - #rss .feedItem .feedDate { 883 - color: #999; 884 - font-size: 0.9em; 885 - margin-top: 10px; 886 - } 887 - 888 - /* Thanks Section Styling */ 889 - #thanks-content { 890 - color: #e6e6e6; 891 - line-height: 1.8; 892 - font-size: 0.95em; 893 - } 894 - 895 - #thanks-content a { 896 - color: #b3b3ff; 897 - text-decoration: none; 898 - transition: color 0.3s ease; 899 - } 900 - 901 - #thanks-content a:hover { 902 - color: #d4d4ff; 903 - text-decoration: underline; 904 - } 905 - 906 - /* Responsive breakpoints */ 907 - @media (max-width: 1024px) { 908 - .gallery { 909 - grid-template-columns: repeat(3, 1fr); /* 3 columns on tablets */ 910 - } 911 - } 912 - 913 - @media (max-width: 768px) { 914 - .gallery { 915 - grid-template-columns: repeat(2, 1fr); /* 2 columns on small tablets */ 916 - } 917 - } 918 - 919 - @media (max-width: 480px) { 920 - .gallery { 921 - grid-template-columns: 1fr; /* 1 column (stacked) on mobile */ 922 - gap: 15px; 923 - } 924 - 925 - #simple-photo-gallery { 926 - padding: 15px; 927 - } 928 - } 929 - /* Phone wallpaper */ 930 - @media (max-width: 767px) { 931 - body { 932 - background-image: url("https:imrs.madebydanny.uk?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/site-assets/minimalist-forest-watchtower-sunset-tr6zh724c1z0skyv.jpg"); 933 - background-attachment: fixed; /* Better performance on mobile */ 934 - } 935 - } 936 - #footer img { 937 - width: 100px; 938 - margin-top: 10px; 939 - }
+116
css/v18.css
··· 1 + body { 2 + background-color: black; 3 + color: #fff; 4 + font-family: "Indie Flower", cursive; 5 + font-weight: 600; 6 + font-style: normal; 7 + } 8 + .light-mode{ 9 + background-color: white; 10 + color: black; 11 + font-family: "Indie Flower", cursive; 12 + font-weight: 600; 13 + font-style: normal; 14 + } 15 + h3 { 16 + font-family: "Indie Flower", cursive; 17 + font-weight: 600; 18 + font-style: normal; 19 + font-size: 30px; 20 + } 21 + subtitle { 22 + font-family: "Indie Flower", cursive; 23 + font-weight: 600; 24 + font-style: normal; 25 + font-size: 32px; 26 + } 27 + h2 { 28 + font-family: "Indie Flower", cursive; 29 + font-weight: 600; 30 + font-style: normal; 31 + font-size: 35px; 32 + } 33 + nav ul { 34 + list-style-type: none; 35 + margin: 0; 36 + padding: 0; 37 + overflow: hidden; 38 + } 39 + nav ul li { 40 + float: left; 41 + } 42 + nav ul li a { 43 + display: block; 44 + color: rgb(218, 12, 218); 45 + text-align: center; 46 + padding: 14px 16px; 47 + text-decoration: none; 48 + font-family: "Indie Flower", cursive; 49 + font-weight: 600; 50 + font-style: normal; 51 + } 52 + .light-mode nav ul li a:hover { 53 + color:black; 54 + } 55 + nav ul li a:hover { 56 + color:white; 57 + } 58 + .column { 59 + float: left; 60 + height: 300px; 61 + height: 100vh; 62 + width: 80%; 63 + } 64 + @media only screen and (max-width: 720px) { 65 + .column { 66 + width: 100%; 67 + } 68 + } 69 + .row:after { 70 + content: ""; 71 + display: table; 72 + clear: both; 73 + } 74 + a { 75 + color: blueviolet; 76 + text-decoration: none; 77 + } 78 + a:hover { 79 + color: white; 80 + text-decoration: underline; 81 + } 82 + .light-mode a:hover { 83 + color: black; 84 + text-decoration: underline; 85 + } 86 + p i { 87 + color:red 88 + } 89 + ul li i:hover { 90 + color:white; 91 + } 92 + p i:hover { 93 + color:white; 94 + } 95 + p i a { 96 + color:red 97 + } 98 + p i a:hover { 99 + color:white; 100 + } 101 + footer i a { 102 + color:blueviolet; 103 + } 104 + .status { 105 + border-bottom: dashed 2px rgb(218, 12, 218) 106 + } 107 + .status p { 108 + padding: 3px; 109 + } 110 + hr { 111 + border: dashed 2px rgb(218, 12, 218); 112 + } 113 + .loading { 114 + opacity: 0.6; 115 + font-style: italic; 116 + }
docs.html cdn/docs.html
+16
img.md
··· 1 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img1.jpg" alt="Placeholder Image 1" class="gallery-item" loading="lazy"> 2 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img10.jpg" alt="Placeholder Image 2" class="gallery-item" loading="lazy"> 3 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img11.png" alt="Placeholder Image 3" class="gallery-item" loading="lazy"> 4 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img12.jpg" alt="Placeholder Image 4" class="gallery-item" loading="lazy"> 5 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img13.png" alt="Placeholder Image 6" class="gallery-item" loading="lazy"> 6 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img14.png" alt="Placeholder Image 7" class="gallery-item" loading="lazy"> 7 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img15.png" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 8 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img16.png" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 9 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img2.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 10 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img3.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 11 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img4.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 12 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img5.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 13 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img6.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 14 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img7.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 15 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img8.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 16 + <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img9.jpg" alt="Placeholder Image 6" class="gallery-item" loading="lazy">
+100 -133
index.html
··· 1 1 <!DOCTYPE html> 2 2 <html lang="en"> 3 3 <head> 4 - <meta charset="UTF-8"> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 - 7 - <title>Daniel Morrisey - Home</title> 8 - <meta name="description" id="meta-description" content="Posting everything into the endless jet stream of posts"> 9 - 10 - <!-- Performance: Resource Hints --> 11 - <link rel="dns-prefetch" href="https://mbdio.uk"> 12 - <link rel="preconnect" href="https://mbdio.uk" crossorigin> 13 - <link rel="dns-prefetch" href="https://public.api.bsky.app"> 14 - <link rel="preconnect" href="https://public.api.bsky.app"> 15 - <link rel="dns-prefetch" href="https://api.github.com"> 16 - <link rel="preconnect" href="https://api.github.com"> 17 - <link rel="dns-prefetch" href="https://kit.fontawesome.com"> 18 - <link rel="preconnect" href="https://kit.fontawesome.com" crossorigin> 19 - <link rel="dns-prefetch" href="https://feed.madebydannyuk.workers.dev"> 20 - <link rel="dns-prefetch" href="https://imrs.madebydanny.uk"> 21 - <link rel="dns-prefetch" href="https://cdn.madebydanny.uk"> 22 - <link rel="preconnect" href="https://fonts.googleapis.com"> 23 - <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 24 - <link href="https://fonts.googleapis.com/css2?family=Itim&display=swap" rel="stylesheet"> 25 - 26 - <!-- ✅ SEO Keywords --> 27 - <meta name="keywords" content="Daniel Morrisey, developer, writer, blog, projects, Bluesky, web development, creative work"> 28 - 29 - <!-- ✅ Robots --> 30 - <meta name="robots" content="index, follow"> 31 - 32 - <!-- ✅ Author --> 33 - <meta name="author" content="Daniel Morrisey"> 34 - 35 - <!-- ✅ Canonical URL --> 36 - <link rel="canonical" href="https://madebydanny.uk/"> 37 - 38 - <!-- ✅ Favicon --> 39 - <link rel="icon" id="favicon" href="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/seo/favicon.webp"> 40 - 41 - <!-- ✅ Open Graph --> 42 - <meta property="og:title" content="Daniel Morrisey - Home"> 43 - <meta property="og:description" id="og-description" content="Posting everything into the endless jet stream of posts"> 44 - <meta property="og:type" content="website"> 45 - <meta property="og:url" content="https://madebydanny.uk/"> 46 - <meta property="og:image" id="og-image" content="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/seo/og-img.png"> 47 - <script src="https://kit.fontawesome.com/0ca27f8db1.js" crossorigin="anonymous" defer></script> 48 - <link rel="stylesheet" href="css/index.css"> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title>madebydanny.uk</title> 7 + <!--Site SEO--> 8 + <link rel="icon" id="favicon" href="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/seo/favicon.webp"> 9 + <meta name="description" id="meta-description" content="Posting everything into the endless jet stream of posts"> 10 + <!--Social SEO--> 11 + <meta property="og:title" content="madebydanny.uk"> 12 + <meta property="og:description" id="og-description" content="Posting everything into the endless jet stream of posts"> 13 + <meta property="og:type" content="website"> 14 + <meta property="og:url" content="https://madebydanny.uk/"> 15 + <meta property="og:image" id="og-image" content="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/seo/og-img.png"> 16 + <!--Google Fonts--> 17 + <script src="https://kit.fontawesome.com/0ca27f8db1.js" crossorigin="anonymous"></script> 18 + <link rel="preconnect" href="https://fonts.googleapis.com"> 19 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 20 + <link href="https://fonts.googleapis.com/css2?family=Alan+Sans:wght@300..900&family=Indie+Flower&display=swap" rel="stylesheet"> 21 + <link rel="stylesheet" href="/css/v18.css"> 22 + <style> 23 + </style> 49 24 </head> 50 25 <body> 51 - <div class="center"> 52 - <div class="white-card" id="current-status" style="margin-bottom: 20px; text-align: center;"> 53 - <b>Current Status:</b> Loading... 54 - </div> 55 - <div class="top-section"> 56 - <div class="bsky-profile-header"> 57 - <img id="banner" alt="Profile banner"> 58 - <div class="bsky-header-content"> 59 - <img id="pfp" alt="Profile picture"> 60 - <div class="bsky-info"> 61 - <div id="user"></div> 62 - <div id="handle"></div> 63 - <div id="bio"></div> 64 - <div id="stats"></div> 65 - <a href="/followonbsky.html?did=did:plc:l37td5yhxl2irrzrgvei4qay" target="_blank" class="bsky-button"> 66 - View on Bluesky 67 - </a> 68 - <br><br> 69 - </div> 70 - </div> 26 + <div id="google_translate_element"></div> 27 + <nav> 28 + <ul> 29 + <li><a onclick="myFunction()">Toggle dark mode</a></li> 30 + <li><a href="/followonbsky?did=madebydanny.uk">Bluesky</a></li> 31 + <li><a href="https://blog.madebydanny.uk">Blog</a></li> 32 + <li><a href="#socials">Socials</a></li> 33 + <li><a href="#projects">Projects</a></li> 34 + <li><a href="https://altly.madebydanny.uk">ALTly</a></li> 35 + <li><a href="/cdn/index.html">MBD CDN</a></li> 36 + </ul> 37 + </nav> 38 + <div class="row"> 39 + <div class="column"> 40 + <div class="status"> 41 + <p><i>Current Status:</i> <span id="status-content" class="loading">Loading...</span></p> 42 + <p>View status history on <a href="https://kibun.social/users/madebydanny.uk">kibun.social</a></p> 71 43 </div> 72 - 73 - <div id="latest-bsky-post"> 74 - <div class="bsky-loading">Loading latest post...</div> 75 - </div> 76 - </div> 77 - 78 - <div id="projects" class="white-card" style="margin-top: 20px;"> 79 - <p>Loading projects...</p> 80 - </div> 81 - <div id="tangled-repo" class="white-card" style="margin-top: 20px;"> 82 - <p>Loading tangled repository...</p> 83 - </div> 84 - <div id="leaflets" class="white-card" style="margin-top: 20px;"> 85 - <h2><i class="fa-solid fa-rss"></i> Latest Leaflets</h2> 86 - <div id="rss"></div> 87 - </div> 88 - <div class="content-section"> 89 - <section id="simple-photo-gallery"> 90 - <h2><i class="fa-solid fa-images"></i> Pined Photos</h2> 91 - <div class="gallery"> 92 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img1.jpg" alt="Placeholder Image 1" class="gallery-item" loading="lazy"> 93 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img10.jpg" alt="Placeholder Image 2" class="gallery-item" loading="lazy"> 94 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img11.png" alt="Placeholder Image 3" class="gallery-item" loading="lazy"> 95 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img12.jpg" alt="Placeholder Image 4" class="gallery-item" loading="lazy"> 96 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img13.png" alt="Placeholder Image 6" class="gallery-item" loading="lazy"> 97 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img14.png" alt="Placeholder Image 7" class="gallery-item" loading="lazy"> 98 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img15.png" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 99 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img16.png" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 100 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img2.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 101 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img3.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 102 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img4.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 103 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img5.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 104 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img6.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 105 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img7.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 106 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img8.jpg" alt="Placeholder Image 8" class="gallery-item" loading="lazy"> 107 - <img src="https://imrs.madebydanny.uk/?url=https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/photos/img9.jpg" alt="Placeholder Image 6" class="gallery-item" loading="lazy"> 44 + <h2>welcome to my tiny website</h2> 45 + <p>Hi, I'm Daniel Morrisey. Posting on Bluesky is my part time job and I love to play Stardew Valley and Raft.</p> 46 + <p>You can find me on Bluesky <i>(the best social media platform)</i>, but I'm also on Threads and Mastodon <i><a href="#socials">(view my social links)</a></i> I run my own Bluesky PDS that you can use if you want to, just DM me on Bluesky or email me.</p> 47 + <hr> 48 + <h3>things to do</h3> 49 + <p>Things you can do and cool websites you can checkout</p> 50 + <ul> 51 + <li><a href="https://madebydanny.uk/followonbsky?did=madebydanny.uk">Follow me on Bluesky</a></li> 52 + <li><a href="#projects">Checkout my projects</a></li> 53 + <li><a href="#leaflets">Read my blog</a></li> 54 + </ul> 55 + <hr> 56 + <h3>AT Links</h3> 57 + <p>Social links for AT Protocol apps</p> 58 + <ul> 59 + <li><a target="_blank" href="https://blog.madebydanny.uk">Leaflet</a></li> 60 + <li><a target="_blank" href="https://tangled.org/madebydanny.uk">Tangled</a></li> 61 + <li><a target="_blank" href="https://kibun.social/users/madebydanny.uk">Kibun</a></li> 62 + </ul> 63 + <hr> 64 + <h3 id="socials">social links</h3> 65 + <p>Here are my socials but <b>I mostly use Bluesky</b> so follow me there</p> 66 + <ul id="socials"> 67 + <li><a target="_blank"href="https://madebydanny.uk/followonbsky?did=alt.pds.madebydanny.uk"><i class="fa-brands fa-bluesky"></i> - Bluesky ALT <i>(@alt.pds.madebydanny.uk)</i></a></li> 68 + <li><a target="_blank"href="https://madebydanny.uk/followonbsky?did=madebydanny.uk"><i class="fa-brands fa-bluesky"></i> - Bluesky Main <i>(@madebydanny.uk)</i></a></li> 69 + <li><a target="_blank"href="https://threads.com/madebydanny.uk"><i class="fa-brands fa-threads"></i> - Threads</a></li> 70 + <li><a target="_blank"href="https://mastodon.social/@danielmorrisey"><i class="fa-brands fa-mastodon"></i> - Mastodon<i>.social</i></a></li> 71 + <li><a target="_blank"href="https://writing.madebydanny.uk"><i class="fa-brands fa-medium"></i> - Medium</a></li> 72 + </ul> 73 + <hr> 74 + <h3 id="projects">projects</h3> 75 + <p>Simple projects and tools made by me, <i>(<a target="_blank" href="https://tangled.org/madebydanny.uk">all code is public on Tangled</a>)</i></p> 76 + <ul> 77 + <li><a target="_blank" href="https://altly.madebydanny.uk"><b>ATLly</b></a> - Make social media alt text using Claude Sonnet 4.5</li> 78 + <li><a target="_blank" href="https://madebydanny.uk/followonbsky?did=claude.altq.net"><b>Claude for Bluesky</b></a> - A simple bluesky bot you can "@" to ask questions and get a responce from Claude Sonnet 4.5</li> 79 + <li><a target="_blank" href="https://lamppost.madebydanny.uk"><b>Lamppost</b></a> - Generate images using Stable Diffusion <i>(ai)</i> for free</li> 80 + <li><a target="_blank" href="/cdn/index.html"><b>MBD CDN</b></a> - A free for life CDN powered by the Cloudflare network</li> 81 + </ul> 82 + <hr> 83 + <h3 id="leaflets">newest leaflets</h3> 84 + <p>A feed for my Leaflet pub, <a href="https://blog.madebydanny.uk">Daniel's Notes & Thoughts</a></p> 85 + <ul id="leaflet-feed" class="loading"> 86 + <li>Loading blog posts...</li> 87 + </ul> 88 + <hr> 89 + <h3 id="tangled">pinned tangled repos</h3> 90 + <p>The pinned repos from <a target="_blank" href="https://tangled.org/madebydanny.uk">my Tangled account</a></p> 91 + <ul id="tangled-repos" class="loading"> 92 + <li>Loading repositories...</li> 93 + </ul> 94 + <hr> 95 + <h3>made possible thanks to</h3> 96 + <p><a href="https://madebydanny.uk/followonbsky.html?did=tangled.org">@tangled.org</a>, <a href="https://madebydanny.uk/followonbsky.html?did=wisp.place">@wisp.place</a>, <a href="https://madebydanny.uk/followonbsky.html?did=nekomimi.pet">@nekomimi.pet</a>, <a href="https://madebydanny.uk/followonbsky.html?did=juli.ee">@juli.ee</a>, <a href="https://lovable.dev">lovable.dev</a>, <a href="https://pdsls.dev">@pdsls.dev</a>, <a href="https://cloudflare.com">cloudflare.com</a>, <a href="https://madebydanny.uk/followonbsky.html?did=/vscode.dev">@vscode.dev</a>, <a href="https://github.com">Github</a>, <a href="https://madebydanny.uk/followonbsky.html?did=j4ck.xyz">@j4ck.xyz</a>, <a href="/followonbsky.html?did=upcloud.com">@upcloud.com</a>, <a href="https://tailscale.com">tailscale.com</a>, <a href="https://raspberrypi.com">raspberrypi.com</a>, <a href="https://ubuntu.com">Ubuntu</a>, <a href="https://apple.com">Apple</a>, <a href="https://reddit.com">Reddit</a>, <a href="www.youtube.com/@LinusTechTips">Linus Tech Tips</a>, <a href="https://w3schools.com">W3Schools</a> and you 97 + <hr> 98 + <footer> 99 + <subtitle>:)</subtitle> 100 + <p>&copy;2024 madebydanny.uk, by <i><a href="https://madebydanny.uk/followonbsky?did=madebydanny.uk">Daniel Morrisey</a></i> <b>-</b> Hosted on <a href="https://madebydanny.uk/followonbsky?did=wisp.place">@wisp.place</a> <b>-</b> View site <a href="https://tangled.org/madebydanny.uk/website">Code on Tangled</a></p> 101 + </footer> 108 102 </div> 109 - </section> 110 103 </div> 111 - <div id="thanks" class="white-card" style="margin-top: 20px;"> 112 - <h2><i class="fa-solid fa-heart"></i> Made Possible Thanks To</h2> 113 - Made possible thanks to <a href="https://madebydanny.uk/followonbsky.html?did=tangled.org">@tangled.org</a>, <a href="https://madebydanny.uk/followonbsky.html?did=wisp.place">@wisp.place</a>, <a href="https://madebydanny.uk/followonbsky.html?did=nekomimi.pet">@nekomimi.pet</a>, <a href="https://madebydanny.uk/followonbsky.html?did=juli.ee">@juli.ee</a>, <a href="https://lovable.dev">lovable.dev</a>, <a href="https://pdsls.dev">@pdsls.dev</a>, <a href="https://cloudflare.com">cloudflare.com</a>, <a href="https://madebydanny.uk/followonbsky.html?did=/vscode.dev">@vscode.dev</a>, <a href="https://github.com">@github.com</a>, <a href="https://madebydanny.uk/followonbsky.html?did=jack.xyz">jack.xyz</a>, <a href="https://upcloud.com">upcloud.com</a>, <a href="https://tailscale.com">tailscale.com</a>, <a href="https://raspberrypi.com">raspberrypi.com</a>, <a href="https://ubuntu.com">Ubuntu</a>, <a href="https://apple.com">Apple</a>, <a href="https://reddit.com">Reddit</a>, <a href="www.youtube.com/@LinusTechTips">Linus Tech Tips</a>, <a href="https://w3schools.com">W3Schools</a> and you 114 - </div> 115 - <div id="footer" class="white-card"> 116 - &copy;2024-25 Daniel Morrisey, Powered by the <a href="https://atproto.com">AT Protocol</a>, <a href="https://upcloud.com">UpCloud</a> & <a href="https://cloudflare.com">Cloudflare</a> 117 - <br> 118 - <!-- Default Statcounter code for Made by Danny UK 119 - https://madebydanny.uk --> 120 104 <script type="text/javascript"> 121 - var sc_project=13180172; 122 - var sc_invisible=0; 123 - var sc_security="a4ed014f"; 124 - var scJsHost = "https://"; 125 - document.write("<sc"+"ript type='text/javascript' src='" + 126 - scJsHost+ 127 - "statcounter.com/counter/counter.js'></"+"script>"); 105 + function googleTranslateElementInit() { 106 + new google.translate.TranslateElement({pageLanguage: 'en', layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element'); 107 + } 128 108 </script> 129 - <noscript><div class="statcounter"><a title="Web Analytics 130 - Made Easy - Statcounter" href="https://statcounter.com/" 131 - target="_blank"><img class="statcounter" 132 - src="https://c.statcounter.com/13180172/0/a4ed014f/0/" 133 - alt="Web Analytics Made Easy - Statcounter" 134 - referrerPolicy="no-referrer-when-downgrade"></a></div></noscript> 135 - <!-- End of Statcounter Code --> 136 - <a href="https://creativecommons.org/licenses/by-nc/4.0/deed"> 137 - <img src="https://public-cdn.madebydanny.uk/user-content/2025-11-24/1764019990785_by-nc.svg" alt="Made by Danny UK Logo"> 138 - </a> 139 - </div> 140 - <button onclick="topFunction()" id="myBtn" title="Go to top"><i class="fa-solid fa-arrow-up"></i></button> 141 - <script src="https://feed.madebydannyuk.workers.dev/embed.js" async></script> 142 - 143 - <script src="js/index.js" defer></script> 109 + <script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script> 110 + <script src="/js/v18.js"></script> 144 111 </body> 145 112 </html>
+2 -1
js/bsky.js
··· 11 11 { name: "Nooki", base: "https://nooki.me/user/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/nooki.webp", cls: "nooki" }, 12 12 { name: "Stream Place", base: "https://stream.place/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/splace.ico", cls: "splace" }, 13 13 { name: "Bitchsky", base: "https://bitchsky.app/profile/", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/bitch.svg", cls: "bitch" }, 14 - { name: "PDSls", base: "https://pdsls.dev/at://", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/pdsls.webp", cls: "bsky" }, 14 + { name: "PDSls", base: "https://pdsls.dev/at://", icon: "https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/followonbsky/pdsls.webp", cls: "bsky" }, 15 + 15 16 ]; 16 17 17 18 const avatarEl = document.getElementById('avatar');
-534
js/index.js
··· 1 - // ============================================ 2 - // SCROLL TO TOP FUNCTIONALITY 3 - // ============================================ 4 - 5 - let mybutton = document.getElementById("myBtn"); 6 - 7 - window.onscroll = function() {scrollFunction()}; 8 - 9 - function scrollFunction() { 10 - if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) { 11 - mybutton.style.display = "block"; 12 - } else { 13 - mybutton.style.display = "none"; 14 - } 15 - } 16 - 17 - function topFunction() { 18 - document.body.scrollTop = 0; 19 - document.documentElement.scrollTop = 0; 20 - } 21 - 22 - // ============================================ 23 - // GITHUB API - LAST UPDATED 24 - // ============================================ 25 - 26 - async function fetchLastUpdated() { 27 - const repo = "therealfuntimeswithdanny/danielmorrisey"; 28 - const apiUrl = `https://api.github.com/repos/${repo}`; 29 - try { 30 - const response = await fetch(apiUrl); 31 - if (!response.ok) throw new Error("GitHub API error"); 32 - const data = await response.json(); 33 - const updated = new Date(data.pushed_at); 34 - const formatted = updated.toLocaleString("en-US", { 35 - year: "numeric", 36 - month: "short", 37 - day: "numeric", 38 - hour: "2-digit", 39 - minute: "2-digit", 40 - second: "2-digit", 41 - hour12: false 42 - }); 43 - document.getElementById("lastUpdated").textContent = formatted; 44 - } catch (err) { 45 - document.getElementById("lastUpdated").textContent = "Faild to reach Bluesky PDS pds.madebydanny.uk"; 46 - console.error(err); 47 - } 48 - } 49 - 50 - // ============================================ 51 - // BLUESKY API - PROFILE 52 - // ============================================ 53 - 54 - async function fetchBlueskyProfile() { 55 - const did = 'did:plc:l37td5yhxl2irrzrgvei4qay'; 56 - const apiUrl = `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${did}`; 57 - 58 - try { 59 - const response = await fetch(apiUrl); 60 - if (!response.ok) throw new Error('Faild to reach Bluesky PDS pds.madebydanny.uk'); 61 - 62 - const data = await response.json(); 63 - 64 - document.querySelector('.bsky-loading').style.display = 'none'; 65 - 66 - const bannerElement = document.getElementById('banner'); 67 - const pfpElement = document.getElementById('pfp'); 68 - const userElement = document.getElementById('user'); 69 - const handleElement = document.getElementById('handle'); 70 - const bioElement = document.getElementById('bio'); 71 - const statsElement = document.getElementById('stats'); 72 - 73 - // Update SEO meta tags 74 - const metaDescription = document.getElementById('meta-description'); 75 - const ogDescription = document.getElementById('og-description'); 76 - const favicon = document.getElementById('favicon'); 77 - const ogImage = document.getElementById('og-image'); 78 - 79 - if (data.description) { 80 - metaDescription.setAttribute('content', data.description); 81 - ogDescription.setAttribute('content', data.description); 82 - } 83 - 84 - if (data.avatar) { 85 - favicon.setAttribute('href', data.avatar); 86 - pfpElement.src = data.avatar; 87 - pfpElement.style.display = 'block'; 88 - } 89 - 90 - if (data.banner) { 91 - ogImage.setAttribute('content', data.banner); 92 - bannerElement.src = data.banner; 93 - bannerElement.style.display = 'block'; 94 - } else { 95 - bannerElement.style.display = 'block'; 96 - } 97 - 98 - userElement.textContent = data.displayName || data.handle || 'Faild to reach Bluesky PDS pds.madebydanny.uk'; 99 - handleElement.textContent = '@' + data.handle; 100 - bioElement.textContent = data.description || 'Faild to reach Bluesky PDS pds.madebydanny.uk'; 101 - 102 - statsElement.innerHTML = ` 103 - <div><span>${data.postsCount || 0}</span> Posts</div> 104 - <div><span>${data.followersCount || 0}</span> Followers</div> 105 - <div><span>${data.followsCount || 0}</span> Following</div> 106 - `; 107 - 108 - } catch (error) { 109 - console.error('Error fetching Bluesky profile:', error); 110 - document.querySelector('.bsky-loading').textContent = 'Faild to reach Bluesky PDS pds.madebydanny.uk'; 111 - } 112 - } 113 - 114 - // ============================================ 115 - // UTILITY FUNCTIONS 116 - // ============================================ 117 - 118 - function formatTimeAgo(date) { 119 - const now = new Date(); 120 - const diffMs = now - date; 121 - const diffMins = Math.floor(diffMs / 60000); 122 - const diffHours = Math.floor(diffMs / 3600000); 123 - const diffDays = Math.floor(diffMs / 86400000); 124 - 125 - if (diffMins < 1) return 'just now'; 126 - if (diffMins < 60) return `${diffMins}m ago`; 127 - if (diffHours < 24) return `${diffHours}h ago`; 128 - return `${diffDays}d ago`; 129 - } 130 - 131 - function linkifyText(text) { 132 - if (!text) return ''; 133 - 134 - const urlPattern = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; 135 - 136 - return text.replace(urlPattern, (url) => { 137 - return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`; 138 - }); 139 - } 140 - 141 - function createProfileLink(handle, displayName) { 142 - const did = handle; 143 - return `<a href="/followonbsky.html?did=${did}" target="_blank" style="text-decoration: none; color: inherit;">${displayName}</a>`; 144 - } 145 - 146 - // ============================================ 147 - // BLUESKY API - LATEST POST 148 - // ============================================ 149 - 150 - async function fetchLatestPost() { 151 - const did = 'did:plc:l37td5yhxl2irrzrgvei4qay'; 152 - const apiUrl = `https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=${did}&limit=1`; 153 - 154 - try { 155 - const response = await fetch(apiUrl); 156 - if (!response.ok) throw new Error('Faild to reach Bluesky PDS pds.madebydanny.uk'); 157 - 158 - const data = await response.json(); 159 - 160 - if (!data.feed || data.feed.length === 0) { 161 - document.getElementById('latest-bsky-post').innerHTML = '<p>Faild to reach Bluesky PDS pds.madebydanny.uk</p>'; 162 - return; 163 - } 164 - 165 - const feedItem = data.feed[0]; 166 - const post = feedItem.post; 167 - const author = post.author; 168 - const record = post.record; 169 - 170 - let postHTML = ''; 171 - 172 - if (record.reply && record.reply.parent) { 173 - try { 174 - const parentUri = record.reply.parent.uri; 175 - const parentResponse = await fetch(`https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=${encodeURIComponent(parentUri)}`); 176 - 177 - if (parentResponse.ok) { 178 - const parentData = await parentResponse.json(); 179 - const parentPost = parentData.thread.post; 180 - const parentAuthor = parentPost.author; 181 - const parentRecord = parentPost.record; 182 - 183 - const parentDate = new Date(parentPost.indexedAt); 184 - const parentTimeAgo = formatTimeAgo(parentDate); 185 - 186 - postHTML += ` 187 - <div style="opacity: 0.8; border-left: 3px solid #2F7D61; padding-left: 15px; margin-bottom: 15px;"> 188 - <div class="post-header"> 189 - <a href="/followonbsky.html?did=${parentAuthor.handle}" target="_blank" style="text-decoration: none;"> 190 - <img src="https://imrs.madebydanny.uk?url=${parentAuthor.avatar || ''}" alt="Avatar" class="post-avatar"> 191 - </a> 192 - <div class="post-user-info"> 193 - <div class="post-display-name"> 194 - <a href="/followonbsky.html?did=${parentAuthor.handle}" target="_blank" style="text-decoration: none; color: inherit;"> 195 - ${parentAuthor.displayName || parentAuthor.handle} 196 - </a> 197 - </div> 198 - <div class="post-handle"> 199 - <a href="/followonbsky.html?did=${parentAuthor.handle}" target="_blank" style="text-decoration: none; color: inherit;"> 200 - @${parentAuthor.handle} 201 - </a> 202 - </div> 203 - </div> 204 - <div class="post-timestamp">${parentTimeAgo}</div> 205 - </div> 206 - <div class="post-text">${linkifyText(parentRecord.text || '')}</div> 207 - </div> 208 - <div style="color: #2F7D61; font-size: 13px; margin-bottom: 10px;"> 209 - <i class="fa-solid fa-reply"></i> Replying to <a href="/followonbsky.html?did=${parentAuthor.handle}" target="_blank" style="color: inherit;">@${parentAuthor.handle}</a> 210 - </div> 211 - `; 212 - } 213 - } catch (error) { 214 - console.error('Error fetching parent post:', error); 215 - } 216 - } 217 - 218 - const postDate = new Date(post.indexedAt); 219 - const timeAgo = formatTimeAgo(postDate); 220 - 221 - postHTML += ` 222 - <div class="post-header"> 223 - <a href="/followonbsky.html?did=${author.handle}" target="_blank" style="text-decoration: none;"> 224 - <img src="https://imrs.madebydanny.uk?url=${author.avatar || ''}" alt="Avatar" class="post-avatar"> 225 - </a> 226 - <div class="post-user-info"> 227 - <div class="post-display-name"> 228 - <a href="/followonbsky.html?did=${author.handle}" target="_blank" style="text-decoration: none; color: inherit;"> 229 - ${author.displayName || author.handle} 230 - </a> 231 - </div> 232 - <div class="post-handle"> 233 - <a href="/followonbsky.html?did=${author.handle}" target="_blank" style="text-decoration: none; color: inherit;"> 234 - @${author.handle} 235 - </a> 236 - </div> 237 - </div> 238 - <div class="post-timestamp">${timeAgo}</div> 239 - </div> 240 - <div class="post-text">${linkifyText(record.text || '')}</div> 241 - `; 242 - 243 - if (post.embed) { 244 - if (post.embed.$type === 'app.bsky.embed.images#view') { 245 - postHTML += '<div class="post-embed">'; 246 - post.embed.images.forEach(img => { 247 - postHTML += `<img src="${img.fullsize}" alt="${img.alt || 'Post image'}">`; 248 - }); 249 - postHTML += '</div>'; 250 - } else if (post.embed.$type === 'app.bsky.embed.external#view') { 251 - const ext = post.embed.external; 252 - postHTML += ` 253 - <div class="post-embed"> 254 - <a href="${ext.uri}" target="_blank" rel="noopener noreferrer" class="post-embed-external"> 255 - ${ext.thumb ? `<img src="${ext.thumb}" alt="Link thumbnail">` : ''} 256 - <div class="post-embed-text"> 257 - <div class="post-embed-title">${ext.title || ''}</div> 258 - <div class="post-embed-description">${ext.description || ''}</div> 259 - <div class="post-embed-url">${ext.uri || ''}</div> 260 - </div> 261 - </a> 262 - </div> 263 - `; 264 - } 265 - } 266 - 267 - postHTML += ` 268 - <div class="post-stats"> 269 - <div><i class="fa-regular fa-comment"></i>${post.replyCount || 0}</div> 270 - <div><i class="fa-solid fa-retweet"></i>${post.repostCount || 0}</div> 271 - <div><i class="fa-regular fa-heart"></i>${post.likeCount || 0}</div> 272 - </div> 273 - <a href="https://bsky.app/profile/${author.handle}/post/${post.uri.split('/').pop()}" target="_blank" class="view-post-link">View on Bluesky →</a> 274 - `; 275 - 276 - document.getElementById('latest-bsky-post').innerHTML = postHTML; 277 - 278 - } catch (error) { 279 - console.error('Error fetching latest post:', error); 280 - document.getElementById('latest-bsky-post').innerHTML = '<p>Error loading post</p>'; 281 - } 282 - } 283 - 284 - // ============================================ 285 - // CUSTOM PDS API - ABOUT SECTION 286 - // ============================================ 287 - 288 - async function fetchAbout() { 289 - const apiUrl = 'https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=uk.madebydanny.about&rkey=3m52wrxl4c52b'; 290 - 291 - try { 292 - const response = await fetch(apiUrl); 293 - if (!response.ok) throw new Error('Failed to fetch about'); 294 - 295 - const data = await response.json(); 296 - const aboutElement = document.getElementById('about'); 297 - 298 - if (data.value && data.value.text) { 299 - const formattedText = data.value.text 300 - .split('\n') 301 - .map(paragraph => paragraph.trim()) 302 - .filter(paragraph => paragraph.length > 0) 303 - .map(paragraph => `<p>${paragraph}</p>`) 304 - .join(''); 305 - 306 - aboutElement.innerHTML = formattedText; 307 - } else { 308 - aboutElement.innerHTML = '<p>No about information available</p>'; 309 - } 310 - 311 - } catch (error) { 312 - console.error('Error fetching about:', error); 313 - document.getElementById('about').innerHTML = '<p>Error loading about information</p>'; 314 - } 315 - } 316 - 317 - // ============================================ 318 - // CUSTOM PDS API - TEXT ELEMENTS 319 - // ============================================ 320 - 321 - async function fetchTexts() { 322 - const textElements = document.querySelectorAll('[data-rkey]'); 323 - 324 - for (const element of textElements) { 325 - const rkey = element.getAttribute('data-rkey'); 326 - const apiUrl = `https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=uk.madebydanny.text&rkey=${rkey}`; 327 - 328 - try { 329 - const response = await fetch(apiUrl); 330 - if (!response.ok) throw new Error('Failed to fetch text'); 331 - 332 - const data = await response.json(); 333 - if (data.value && data.value.content) { 334 - if (data.value.format === 'html-lite') { 335 - element.innerHTML = data.value.content; 336 - } else { 337 - element.textContent = data.value.content; 338 - } 339 - } else { 340 - element.textContent = 'No text available'; 341 - } 342 - } catch (error) { 343 - console.error('Error fetching text:', error); 344 - element.textContent = 'Error loading text'; 345 - } 346 - } 347 - } 348 - 349 - // ============================================ 350 - // CUSTOM PDS API - PROJECTS 351 - // ============================================ 352 - 353 - async function fetchProjects() { 354 - const projectsElement = document.querySelector('#projects'); 355 - const apiUrl = 'https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=uk.madebydanny.projects&rkey=3m52x73hzqf2b'; 356 - 357 - try { 358 - const response = await fetch(apiUrl); 359 - if (!response.ok) throw new Error('Failed to fetch projects'); 360 - 361 - const data = await response.json(); 362 - if (data.value && data.value.projects) { 363 - const projectsHtml = data.value.projects.map(project => ` 364 - <div class="project-item"> 365 - <h3><a href="${project.link}" target="_blank">${project.name}</a></h3> 366 - <p>${project.description}</p> 367 - </div> 368 - `).join(''); 369 - projectsElement.innerHTML = `<h2><i class="fa-solid fa-diagram-project"></i> Projects</h2>${projectsHtml}`; 370 - } else { 371 - projectsElement.innerHTML = '<p>No projects available</p>'; 372 - } 373 - } catch (error) { 374 - console.error('Error fetching projects:', error); 375 - projectsElement.innerHTML = '<p>Error loading projects</p>'; 376 - } 377 - } 378 - 379 - // ============================================ 380 - // CUSTOM PDS API - CURRENT STATUS 381 - // ============================================ 382 - 383 - async function fetchCurrentStatus() { 384 - const statusElement = document.getElementById('current-status'); 385 - if (!statusElement) return; 386 - 387 - const apiUrl = 'https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=uk.madebydanny.status&rkey=3m53jj6shtn2b'; 388 - 389 - try { 390 - const response = await fetch(apiUrl); 391 - if (!response.ok) throw new Error('Failed to fetch current status'); 392 - 393 - const data = await response.json(); 394 - if (data.value && data.value.status) { 395 - statusElement.innerHTML = `<b>Current Status:</b> ${data.value.status}`; 396 - } else { 397 - statusElement.innerHTML = '<b>Current Status:</b> No status available'; 398 - } 399 - } catch (error) { 400 - console.error('Error fetching current status:', error); 401 - statusElement.innerHTML = '<b>Current Status:</b> Error loading status'; 402 - } 403 - } 404 - 405 - // ============================================ 406 - // CUSTOM PDS API - TANGLED REPOSITORIES 407 - // ============================================ 408 - 409 - async function fetchTangledRepo() { 410 - const tangledRepoElement = document.querySelector('#tangled-repo'); 411 - const profileUrl = 'https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=sh.tangled.actor.profile&rkey=self'; 412 - 413 - try { 414 - const profileResponse = await fetch(profileUrl); 415 - if (!profileResponse.ok) throw new Error('Failed to fetch tangled profile'); 416 - 417 - const profileData = await profileResponse.json(); 418 - const pinnedRepos = profileData.value.pinnedRepositories || []; 419 - 420 - const validPinnedRepos = pinnedRepos.filter(uri => uri && uri.trim() !== ''); 421 - 422 - if (validPinnedRepos.length === 0) { 423 - tangledRepoElement.innerHTML = '<p>No pinned repositories available</p>'; 424 - return; 425 - } 426 - 427 - const repoPromises = validPinnedRepos.map(async atUri => { 428 - try { 429 - const uriParts = atUri.replace('at://', '').split('/'); 430 - const did = uriParts[0]; 431 - const collection = uriParts[1]; 432 - const rkey = uriParts[2]; 433 - 434 - const repoUrl = `https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=${collection}&rkey=${rkey}`; 435 - const repoResponse = await fetch(repoUrl); 436 - 437 - if (!repoResponse.ok) throw new Error('Failed to fetch repo'); 438 - 439 - const repoData = await repoResponse.json(); 440 - const knot = repoData.value.knot || 'No knot available'; 441 - const name = repoData.value.name || 'No name available'; 442 - const description = repoData.value.description || ''; 443 - const link = description.startsWith('http') ? description : `https://${knot}`; 444 - 445 - let lastCommitDate = null; 446 - 447 - if (link.includes('github.com')) { 448 - try { 449 - const repoPath = link.replace('https://github.com/', ''); 450 - const githubApiUrl = `https://api.github.com/repos/${repoPath}/commits?per_page=1`; 451 - const commitResponse = await fetch(githubApiUrl); 452 - if (commitResponse.ok) { 453 - const commits = await commitResponse.json(); 454 - if (commits && commits.length > 0) { 455 - lastCommitDate = new Date(commits[0].commit.author.date); 456 - } 457 - } 458 - } catch (error) { 459 - console.warn(`Could not fetch commit info for ${name}:`, error); 460 - } 461 - } 462 - 463 - return { knot, name, description, link, lastCommitDate }; 464 - } catch (error) { 465 - console.error(`Error fetching repo ${atUri}:`, error); 466 - return null; 467 - } 468 - }); 469 - 470 - const repos = await Promise.all(repoPromises); 471 - const validRepos = repos.filter(repo => repo !== null); 472 - 473 - if (validRepos.length === 0) { 474 - tangledRepoElement.innerHTML = '<p>No pinned repositories available</p>'; 475 - return; 476 - } 477 - 478 - validRepos.sort((a, b) => { 479 - if (!a.lastCommitDate && !b.lastCommitDate) return 0; 480 - if (!a.lastCommitDate) return 1; 481 - if (!b.lastCommitDate) return -1; 482 - return b.lastCommitDate - a.lastCommitDate; 483 - }); 484 - 485 - const repoItems = validRepos.map(repo => { 486 - let commitInfo = ''; 487 - if (repo.lastCommitDate) { 488 - const timeAgo = formatTimeAgo(repo.lastCommitDate); 489 - commitInfo = `<p style="color: #999; font-size: 0.9em;"><i class="fa-solid fa-clock"></i> Last commit: ${timeAgo}</p>`; 490 - } 491 - 492 - return ` 493 - <div class="tangled-item"> 494 - <h3><a href="${repo.link}" target="_blank">${repo.name}</a></h3> 495 - <p><strong><i class="fa-solid fa-server"></i></strong> ${repo.knot}</p> 496 - ${repo.description ? `<p>${repo.description}</p>` : ''} 497 - ${commitInfo} 498 - </div> 499 - `; 500 - }).join(''); 501 - 502 - tangledRepoElement.innerHTML = `<h2><i class="fa-solid fa-code-branch"></i>Tangled Repositories</h2>${repoItems}`; 503 - } catch (error) { 504 - console.error('Error fetching tangled repo:', error); 505 - tangledRepoElement.innerHTML = '<p>Error loading tangled repository</p>'; 506 - } 507 - } 508 - 509 - // ============================================ 510 - // CLEAR COOKIES AND REFRESH 511 - // ============================================ 512 - 513 - function clearCookiesAndRefresh() { 514 - document.cookie.split(";").forEach(function(c) { 515 - document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/"); 516 - }); 517 - 518 - localStorage.clear(); 519 - sessionStorage.clear(); 520 - location.reload(true); 521 - } 522 - 523 - // ============================================ 524 - // INITIALIZATION - EXECUTE ALL FETCH FUNCTIONS 525 - // ============================================ 526 - 527 - fetchLastUpdated(); 528 - fetchBlueskyProfile(); 529 - fetchLatestPost(); 530 - fetchAbout(); 531 - fetchTexts(); 532 - fetchProjects(); 533 - fetchCurrentStatus(); 534 - fetchTangledRepo();
+129
js/v18.js
··· 1 + async function fetchStatus() { 2 + try { 3 + // First, list all records to find the latest one 4 + const listResponse = await fetch('https://pds.madebydanny.uk/xrpc/com.atproto.repo.listRecords?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=social.kibun.status&limit=1'); 5 + const listData = await listResponse.json(); 6 + 7 + if (listData.records && listData.records.length > 0) { 8 + const latestRecord = listData.records[0]; 9 + const emoji = latestRecord.value.emoji || ''; 10 + const text = latestRecord.value.text || 'No status available'; 11 + document.getElementById('status-content').innerHTML = `${emoji} ${text}`; 12 + document.getElementById('status-content').classList.remove('loading'); 13 + } else { 14 + document.getElementById('status-content').innerHTML = 'No status available'; 15 + document.getElementById('status-content').classList.remove('loading'); 16 + } 17 + } catch (error) { 18 + console.error('Error fetching status:', error); 19 + document.getElementById('status-content').innerHTML = 'Unable to load status'; 20 + document.getElementById('status-content').classList.remove('loading'); 21 + } 22 + } 23 + function myFunction() { 24 + var element = document.body; 25 + element.classList.toggle("light-mode"); 26 + } 27 + // Fetch blog leaflets directly from AT Protocol 28 + async function fetchBlogFeed() { 29 + try { 30 + const response = await fetch('https://pds.madebydanny.uk/xrpc/com.atproto.repo.listRecords?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=pub.leaflet.document&limit=5'); 31 + const data = await response.json(); 32 + 33 + const feedList = document.getElementById('leaflet-feed'); 34 + feedList.innerHTML = ''; 35 + feedList.classList.remove('loading'); 36 + 37 + if (data.records && data.records.length > 0) { 38 + data.records.forEach(record => { 39 + const title = record.value.title || 'Untitled'; 40 + const rkey = record.uri.split('/').pop(); 41 + const link = `https://blog.madebydanny.uk/${rkey}`; 42 + 43 + const li = document.createElement('li'); 44 + const a = document.createElement('a'); 45 + a.href = link; 46 + a.target = '_blank'; 47 + a.textContent = title; 48 + li.appendChild(a); 49 + feedList.appendChild(li); 50 + }); 51 + } else { 52 + feedList.innerHTML = '<li>No blog posts found</li>'; 53 + } 54 + } catch (error) { 55 + console.error('Error fetching blog feed:', error); 56 + document.getElementById('leaflet-feed').innerHTML = '<li>Unable to load blog posts</li>'; 57 + document.getElementById('leaflet-feed').classList.remove('loading'); 58 + } 59 + } 60 + 61 + // Fetch Tangled pinned repos 62 + async function fetchTangledRepos() { 63 + try { 64 + const response = await fetch('https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=did:plc:l37td5yhxl2irrzrgvei4qay&collection=sh.tangled.actor.profile&rkey=self'); 65 + const data = await response.json(); 66 + 67 + if (data.value && data.value.pinnedRepositories) { 68 + const repoList = document.getElementById('tangled-repos'); 69 + repoList.innerHTML = ''; 70 + repoList.classList.remove('loading'); 71 + 72 + const pinnedRepos = data.value.pinnedRepositories.filter(repo => repo && repo.trim() !== ''); 73 + 74 + if (pinnedRepos.length === 0) { 75 + repoList.innerHTML = '<li>No pinned repositories</li>'; 76 + return; 77 + } 78 + 79 + // Fetch details for each pinned repo 80 + for (const repoUri of pinnedRepos) { 81 + try { 82 + const parts = repoUri.replace('at://', '').split('/'); 83 + const did = parts[0]; 84 + const collection = parts[1]; 85 + const rkey = parts[2]; 86 + 87 + const repoResponse = await fetch(`https://pds.madebydanny.uk/xrpc/com.atproto.repo.getRecord?repo=${did}&collection=${collection}&rkey=${rkey}`); 88 + const repoData = await repoResponse.json(); 89 + 90 + if (repoData.value) { 91 + const name = repoData.value.name || 'Unnamed Repository'; 92 + const description = repoData.value.description || ''; 93 + const repoUrl = `https://tangled.org/madebydanny.uk/${rkey}`; 94 + 95 + const li = document.createElement('li'); 96 + const a = document.createElement('a'); 97 + a.href = repoUrl; 98 + a.target = '_blank'; 99 + a.innerHTML = `<b>${name}</b>`; 100 + 101 + if (description) { 102 + a.innerHTML += ` - ${description}`; 103 + } 104 + 105 + li.appendChild(a); 106 + repoList.appendChild(li); 107 + } 108 + } catch (error) { 109 + console.error('Error fetching repo details:', error); 110 + } 111 + } 112 + 113 + if (repoList.children.length === 0) { 114 + repoList.innerHTML = '<li>Unable to load repository details</li>'; 115 + } 116 + } 117 + } catch (error) { 118 + console.error('Error fetching Tangled repos:', error); 119 + document.getElementById('tangled-repos').innerHTML = '<li>Unable to load repositories</li>'; 120 + document.getElementById('tangled-repos').classList.remove('loading'); 121 + } 122 + } 123 + 124 + // Load all dynamic content when page loads 125 + window.addEventListener('DOMContentLoaded', () => { 126 + fetchStatus(); 127 + fetchBlogFeed(); 128 + fetchTangledRepos(); 129 + });
+4 -6
readme.md
··· 22 22 My website is built in HTML, CSS, and JavaScript because I can, and don't have any plans to switch to TypeScript. 23 23 24 24 **Site Preview /index.html** 25 - ![img](https://upcloud.madebydanny.uk/cdn/madebydanny.uk/site-files/readme.md/Screenshot%202025-11-17%20at%2017.54.20.png) 26 - ![img](https://upcloud.madebydanny.uk/cdn/madebydanny.uk/site-files/readme.md/Screenshot%202025-11-17%20at%2017.54.27.png) 27 - ![img](https://upcloud.madebydanny.uk/cdn/madebydanny.uk/site-files/readme.md/Screenshot%202025-11-17%20at%2017.54.34.png) 28 - ![img](https://upcloud.madebydanny.uk/cdn/madebydanny.uk/site-files/readme.md/Screenshot%202025-11-17%20at%2017.54.42.png) 29 - ![img](https://upcloud.madebydanny.uk/cdn/madebydanny.uk/site-files/readme.md/Screenshot%202025-11-17%20at%2017.54.52.png) 25 + ![https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/readme.md/Screenshot%202025-11-25%20at%2017.22.20.png](https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/readme.md/Screenshot%202025-11-25%20at%2017.22.20.png) 26 + ![https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/readme.md/Screenshot%202025-11-25%20at%2017.22.28.png](https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/readme.md/Screenshot%202025-11-25%20at%2017.22.28.png) 27 + ![https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/readme.md/Screenshot%202025-11-25%20at%2017.22.37.png](https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/readme.md/Screenshot%202025-11-25%20at%2017.22.37.png) 30 28 31 29 ## Follow on Bluesky Thing {2} 32 30 A simple tool where anyone can enter a DID *(or handle)* and get a profile photo preview and a list of **top** clients, such as Deer, Anisota, Blacksky, etc., with the option for a custom client that serves profiles at *client.com/profile/handle.com*. 33 31 34 32 Try it 👉 [madebydanny.uk/followonbsky](https://madebydanny.uk/followonbsky.html) 35 33 36 - ![img](https://upcloud.madebydanny.uk/cdn/madebydanny.uk/site-files/readme.md/Screen%20Recording%202025-11-17%20at%2018.15.53.gif) 34 + ![img](https://cloudflareisawesome.madebydanny.uk/madebydanny.uk/readme.md/Screen%20Recording%202025-11-25%20at%2017.30.50.gif) 37 35 ### Current Client List 38 36 - **Bluesky** - [bsky.app](https://bsky.app) 39 37 - **Deer Social** - [deer.social](https://deer.social)