Website for the Lede browser extension.
0
fork

Configure Feed

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

Polish landing sections: focus states, FAQ copy, layout CSS

+322 -56
+1 -5
src/components/sections/EditorialValue.astro
··· 1 - --- 2 - // Product story: editorial blocks, not a card grid. 3 - --- 4 - 5 - <section id="product" class="section section--editorial wrap" aria-labelledby="product-heading"> 1 + <section id="product" class="section section--editorial wrap reveal-scroll" aria-labelledby="product-heading"> 6 2 <header class="section__head"> 7 3 <p class="eyebrow">Product</p> 8 4 <h2 id="product-heading" class="heading-xl">Built for the tab in front of you</h2>
+33 -21
src/components/sections/FAQCompact.astro
··· 6 6 const { tangled } = Astro.props; 7 7 --- 8 8 9 - <section id="faq" class="section section--faq wrap" aria-labelledby="faq-heading"> 9 + <section id="faq" class="section section--faq wrap reveal-scroll" aria-labelledby="faq-heading"> 10 10 <header class="section__head"> 11 11 <p class="eyebrow">FAQ</p> 12 12 <h2 id="faq-heading" class="heading-xl">Quick answers</h2> 13 13 </header> 14 14 <div class="faq-stack"> 15 - <details class="faq-disclosure"> 15 + <details class="faq-disclosure faq-disclosure--animate"> 16 16 <summary>Why isn&apos;t Lede in the store yet?</summary> 17 - <div class="faq-disclosure__body"> 18 - <p> 19 - We&apos;re still in beta and iterating quickly. Installing from the project page keeps early testers close to 20 - the latest fixes while we work toward a store listing. 21 - </p> 17 + <div class="faq-disclosure__collapse"> 18 + <div class="faq-disclosure__collapse-sheet"> 19 + <div class="faq-disclosure__body"> 20 + <p> 21 + We&apos;re still in beta and iterating quickly. Installing from the project page keeps early testers close to 22 + the latest fixes while we work toward a store listing. 23 + </p> 24 + </div> 25 + </div> 22 26 </div> 23 27 </details> 24 - <details class="faq-disclosure"> 28 + <details class="faq-disclosure faq-disclosure--animate"> 25 29 <summary>Does Lede watch everything I read?</summary> 26 - <div class="faq-disclosure__body"> 27 - <p> 28 - No. Lede only looks at the active tab when you open it and run a summary or a question. There isn&apos;t a 29 - background feed of your browsing. 30 - </p> 30 + <div class="faq-disclosure__collapse"> 31 + <div class="faq-disclosure__collapse-sheet"> 32 + <div class="faq-disclosure__body"> 33 + <p> 34 + No. Lede only looks at the active tab when you open it and run a summary or a question. There isn&apos;t a 35 + background feed of your browsing. 36 + </p> 37 + </div> 38 + </div> 31 39 </div> 32 40 </details> 33 - <details class="faq-disclosure"> 34 - <summary>Setup or connection errors</summary> 35 - <div class="faq-disclosure__body"> 36 - <p> 37 - If something won&apos;t connect or the README mentions a setting you don&apos;t recognize, the 38 - <a href={tangled} target="_blank" rel="noopener noreferrer">project page</a> has the latest step-by-step 39 - notes—we keep them with the extension itself. 40 - </p> 41 + <details class="faq-disclosure faq-disclosure--animate"> 42 + <summary>What if something won&apos;t connect?</summary> 43 + <div class="faq-disclosure__collapse"> 44 + <div class="faq-disclosure__collapse-sheet"> 45 + <div class="faq-disclosure__body"> 46 + <p> 47 + If something won&apos;t connect or the README mentions a setting you don&apos;t recognize, the 48 + <a href={tangled} target="_blank" rel="noopener noreferrer">project page</a> has the latest step-by-step 49 + notes—we keep them with the extension itself. 50 + </p> 51 + </div> 52 + </div> 41 53 </div> 42 54 </details> 43 55 </div>
+28 -24
src/components/sections/InstallJourney.astro
··· 39 39 </div> 40 40 </div> 41 41 42 - <details class="disclosure reveal-item" style="--i: 4"> 42 + <details class="disclosure disclosure--animate reveal-item" style="--i: 4"> 43 43 <summary>Step-by-step for Chrome or Firefox</summary> 44 - <div class="disclosure__body install-wrap"> 45 - <div class="install-panel"> 46 - <div> 47 - <h3 class="heading-lg">Chrome</h3> 48 - <ol> 49 - <li>Open <span class="kbd">chrome://extensions/</span></li> 50 - <li>Enable <strong>Developer mode</strong></li> 51 - <li>Click <strong>Load unpacked</strong></li> 52 - <li>Select the extension folder that contains <code class="kbd">manifest.json</code></li> 53 - <li>Optional: shortcuts at <span class="kbd">chrome://extensions/shortcuts</span></li> 54 - </ol> 55 - </div> 56 - <div> 57 - <h3 class="heading-lg">Firefox</h3> 58 - <ol> 59 - <li>Open <span class="kbd">about:debugging#/runtime/this-firefox</span></li> 60 - <li>Click <strong>Load Temporary Add-on</strong></li> 61 - <li>Select <strong>manifest.json</strong> inside the extension folder</li> 62 - <li>Add-ons → gear → <strong>Manage Extension Shortcuts</strong> for the hotkey</li> 63 - </ol> 64 - <p class="firefox-note"> 65 - Temporary add-ons clear when you fully quit Firefox—reload during active dev sessions. 66 - </p> 44 + <div class="disclosure__collapse"> 45 + <div class="disclosure__collapse-sheet"> 46 + <div class="disclosure__body install-wrap"> 47 + <div class="install-panel"> 48 + <div> 49 + <h3 class="heading-lg">Chrome</h3> 50 + <ol> 51 + <li>Open <span class="kbd">chrome://extensions/</span></li> 52 + <li>Enable <strong>Developer mode</strong></li> 53 + <li>Click <strong>Load unpacked</strong></li> 54 + <li>Select the extension folder that contains <code class="kbd">manifest.json</code></li> 55 + <li>Optional: shortcuts at <span class="kbd">chrome://extensions/shortcuts</span></li> 56 + </ol> 57 + </div> 58 + <div> 59 + <h3 class="heading-lg">Firefox</h3> 60 + <ol> 61 + <li>Open <span class="kbd">about:debugging#/runtime/this-firefox</span></li> 62 + <li>Click <strong>Load Temporary Add-on</strong></li> 63 + <li>Select <strong>manifest.json</strong> inside the extension folder</li> 64 + <li>Add-ons → gear → <strong>Manage Extension Shortcuts</strong> for the hotkey</li> 65 + </ol> 66 + <p class="firefox-note"> 67 + Temporary add-ons clear when you fully quit Firefox—reload during active dev sessions. 68 + </p> 69 + </div> 70 + </div> 67 71 </div> 68 72 </div> 69 73 </div>
+1 -1
src/components/sections/PrivacyBand.astro
··· 1 - <section id="privacy" class="section section--dark" aria-labelledby="privacy-heading"> 1 + <section id="privacy" class="section section--dark reveal-scroll" aria-labelledby="privacy-heading"> 2 2 <div class="wrap"> 3 3 <header class="section__head"> 4 4 <p class="eyebrow">Privacy</p>
+1 -1
src/components/sections/UsageMicro.astro
··· 1 - <section id="usage" class="section section--tight-top wrap" aria-labelledby="usage-heading"> 1 + <section id="usage" class="section section--tight-top wrap reveal-scroll" aria-labelledby="usage-heading"> 2 2 <header class="section__head"> 3 3 <p class="eyebrow">In the popup</p> 4 4 <h2 id="usage-heading" class="heading-xl">Three beats</h2>
+21
src/layouts/BaseLayout.astro
··· 48 48 <body> 49 49 <a class="skip-link" href="#main">Skip to content</a> 50 50 <slot /> 51 + <script is:inline> 52 + (function () { 53 + if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; 54 + if (typeof CSS !== "undefined" && CSS.supports && CSS.supports("animation-timeline: view(block)")) return; 55 + var nodes = document.querySelectorAll(".reveal-scroll"); 56 + if (!nodes.length || !("IntersectionObserver" in window)) return; 57 + var io = new IntersectionObserver( 58 + function (entries) { 59 + entries.forEach(function (entry) { 60 + if (!entry.isIntersecting) return; 61 + entry.target.classList.add("reveal-scroll--visible"); 62 + io.unobserve(entry.target); 63 + }); 64 + }, 65 + { rootMargin: "0px 0px -10% 0px", threshold: 0.06 } 66 + ); 67 + nodes.forEach(function (el) { 68 + io.observe(el); 69 + }); 70 + })(); 71 + </script> 51 72 </body> 52 73 </html>
+237 -4
src/styles/global.css
··· 76 76 --radius-pill: 14px; 77 77 78 78 --ease-out: cubic-bezier(0.22, 1, 0.36, 1); 79 + --ease-out-disclosure: cubic-bezier(0.22, 1, 0.36, 1); 79 80 --duration-enter: 0.52s; 81 + --duration-disclosure: 0.42s; 82 + /* Fixed caps for <details> collapse — animating 0fr→1fr is skipped inconsistently in browsers */ 83 + --disclosure-collapse-max: min(92vh, 52rem); 84 + --faq-collapse-max: min(60vh, 22rem); 80 85 --content-max: 70ch; 81 86 --page-gutter: clamp(1rem, 4vw, 2.5rem); 82 87 ··· 375 380 font-weight: 700; 376 381 font-size: 1.125rem; 377 382 letter-spacing: var(--tracking-display); 383 + transition: transform 0.22s var(--ease-out), color 0.18s var(--ease-out); 378 384 } 379 385 380 386 .brand-lockup:hover { 381 387 color: var(--color-ink); 388 + transform: translateY(-1px); 382 389 } 383 390 384 391 .brand-lockup:focus-visible { ··· 411 418 font-size: 0.8125rem; 412 419 text-decoration: none; 413 420 color: var(--color-ink-secondary); 421 + transition: 422 + color 0.18s var(--ease-out), 423 + transform 0.22s var(--ease-out); 414 424 } 415 425 416 426 .nav a:hover { 417 427 color: var(--color-brand); 428 + transform: translateY(-1px); 418 429 } 419 430 420 431 .firefox-note { ··· 444 455 align-items: center; 445 456 justify-content: space-between; 446 457 gap: var(--space-sm); 458 + transition: background-color 0.22s var(--ease-out), color 0.18s var(--ease-out); 459 + } 460 + 461 + .disclosure summary:hover { 462 + background: color-mix(in oklch, var(--color-subtle) 55%, var(--color-canvas)); 463 + } 464 + 465 + .disclosure summary:focus-visible { 466 + outline: var(--focus-ring); 467 + outline-offset: var(--focus-offset); 468 + border-radius: var(--radius-sm); 469 + } 470 + 471 + .disclosure summary:active { 472 + background: color-mix(in oklch, var(--color-subtle) 72%, var(--color-canvas)); 447 473 } 448 474 449 475 .disclosure summary::-webkit-details-marker { ··· 457 483 color: var(--color-brand); 458 484 font-size: 1.1rem; 459 485 line-height: 1; 486 + transition: transform var(--duration-disclosure) var(--ease-out-disclosure); 487 + transform: rotate(0deg); 460 488 } 461 489 462 490 .disclosure[open] summary::after { 463 - content: "–"; 491 + transform: rotate(45deg); 492 + } 493 + 494 + .disclosure.disclosure--animate > .disclosure__collapse { 495 + display: block; 496 + max-height: 0; 497 + overflow: hidden; 498 + transition: max-height var(--duration-disclosure) var(--ease-out-disclosure); 499 + } 500 + 501 + .disclosure.disclosure--animate[open] > .disclosure__collapse { 502 + max-height: var(--disclosure-collapse-max); 503 + } 504 + 505 + .disclosure.disclosure--animate .disclosure__collapse-sheet { 506 + overflow: visible; 464 507 } 465 508 466 509 .disclosure__body { ··· 720 763 opacity: 1 !important; 721 764 transform: none !important; 722 765 } 766 + 767 + .reveal-scroll { 768 + opacity: 1 !important; 769 + transform: none !important; 770 + animation: none !important; 771 + } 772 + 773 + .disclosure.disclosure--animate > .disclosure__collapse, 774 + .faq-disclosure.faq-disclosure--animate > .faq-disclosure__collapse { 775 + transition-duration: 0.01ms; 776 + } 777 + 778 + .disclosure summary::after, 779 + .faq-disclosure summary::after { 780 + transition-duration: 0.01ms; 781 + } 782 + 783 + .journey-strip__cell, 784 + .journey-band--callout, 785 + .editorial-block, 786 + .nav a, 787 + .footer-links a, 788 + .brand-lockup, 789 + .journey-strip__cell a { 790 + transition: none; 791 + } 792 + 793 + .journey-strip__cell:hover, 794 + .journey-strip__cell:active, 795 + .journey-band--callout:hover, 796 + .editorial-block:hover, 797 + .nav a:hover, 798 + .footer-links a:hover, 799 + .brand-lockup:hover, 800 + .journey-strip__cell:hover .journey-strip__num, 801 + .journey-strip__cell a:hover { 802 + transform: none; 803 + } 723 804 } 724 805 725 806 /* ========= Redesign: masthead hero + proof, install journey, editorial ========= */ ··· 763 844 .hero-mast { 764 845 position: relative; 765 846 isolation: isolate; 766 - padding-block: calc(var(--space-2xl) + var(--space-sm)) var(--section-y-hero-tail); 847 + /* Breathing room under the header without pushing the headline down the tall demo column */ 848 + padding-top: clamp(var(--space-md), 2.25vw + 0.65rem, var(--space-xl)); 849 + padding-bottom: var(--section-y-hero-tail); 767 850 border-bottom: 1px solid var(--color-border); 768 851 background: 769 852 radial-gradient(ellipse 85% 65% at 0% 0%, var(--color-brand-soft), transparent 58%), ··· 814 897 .hero-mast__grid { 815 898 grid-template-columns: minmax(0, 1.02fr) minmax(320px, 1.12fr); 816 899 gap: clamp(var(--space-2xl), 4vw, var(--space-3xl)); 817 - align-items: center; 900 + /* Top-align copy with the demo — centering pushed the splash block halfway down the tall iframe */ 901 + align-items: start; 818 902 } 819 903 } 820 904 ··· 894 978 color: var(--color-ink); 895 979 } 896 980 981 + .demo-reset:focus-visible { 982 + outline: var(--focus-ring); 983 + outline-offset: var(--focus-offset); 984 + border-radius: var(--radius-sm); 985 + } 986 + 987 + .demo-reset:active { 988 + color: var(--color-brand); 989 + } 990 + 897 991 @media (prefers-reduced-motion: no-preference) { 898 992 .hero-proof__frame:not(.hero-proof__frame--demo) { 899 993 animation: hero-frame-in 0.85s var(--ease-out) both; ··· 955 1049 color-mix(in oklch, var(--color-subtle) 72%, var(--color-canvas)) 100% 956 1050 ); 957 1051 border-color: color-mix(in oklch, var(--color-brand) 22%, var(--color-border)); 1052 + transition: 1053 + border-color 0.24s var(--ease-out), 1054 + box-shadow 0.24s var(--ease-out), 1055 + transform 0.24s var(--ease-out); 1056 + } 1057 + 1058 + .journey-band--callout:hover { 1059 + border-color: color-mix(in oklch, var(--color-brand) 35%, var(--color-border)); 1060 + box-shadow: 0 10px 28px color-mix(in oklch, var(--color-brand) 8%, transparent); 1061 + transform: translateY(-2px); 958 1062 } 959 1063 960 1064 .journey-band__text { ··· 990 1094 display: flex; 991 1095 flex-direction: column; 992 1096 gap: var(--space-xs); 1097 + transition: 1098 + transform 0.26s var(--ease-out), 1099 + border-color 0.22s var(--ease-out), 1100 + box-shadow 0.26s var(--ease-out), 1101 + background-color 0.22s var(--ease-out); 1102 + } 1103 + 1104 + .journey-strip__cell:hover { 1105 + transform: translateY(-4px); 1106 + border-color: color-mix(in oklch, var(--color-brand) 28%, var(--color-border)); 1107 + box-shadow: 1108 + 0 1px 0 color-mix(in oklch, var(--color-brand) 12%, var(--color-border)), 1109 + 0 14px 36px color-mix(in oklch, var(--color-ink) 6%, transparent); 1110 + background: color-mix(in oklch, var(--color-surface) 92%, var(--color-brand-soft)); 1111 + } 1112 + 1113 + .journey-strip__cell:active { 1114 + transform: translateY(-2px); 993 1115 } 994 1116 995 1117 .journey-strip__num { ··· 999 1121 color: var(--color-brand); 1000 1122 line-height: 0.95; 1001 1123 letter-spacing: -0.03em; 1124 + transition: transform 0.28s var(--ease-out), color 0.22s var(--ease-out); 1125 + } 1126 + 1127 + .journey-strip__cell:hover .journey-strip__num { 1128 + transform: translateY(-2px); 1129 + color: color-mix(in oklch, var(--color-brand) 92%, var(--color-ink)); 1002 1130 } 1003 1131 1004 1132 .journey-strip__title { ··· 1022 1150 font-weight: 600; 1023 1151 font-size: 0.8125rem; 1024 1152 margin-top: var(--space-xs); 1153 + align-self: flex-start; 1154 + transition: color 0.18s var(--ease-out), transform 0.2s var(--ease-out); 1155 + } 1156 + 1157 + .journey-strip__cell a:hover { 1158 + transform: translateX(2px); 1025 1159 } 1026 1160 1027 1161 .section--editorial { ··· 1048 1182 .editorial-block { 1049 1183 padding-top: var(--space-lg); 1050 1184 border-top: 3px solid color-mix(in oklch, var(--color-brand) 52%, var(--color-border)); 1185 + transition: border-color 0.24s var(--ease-out), transform 0.26s var(--ease-out); 1186 + } 1187 + 1188 + .editorial-block:hover { 1189 + border-top-color: color-mix(in oklch, var(--color-brand) 72%, var(--color-border)); 1190 + transform: translateY(-2px); 1051 1191 } 1052 1192 1053 1193 .editorial-block p { ··· 1079 1219 padding-block: clamp(var(--space-md), 2.5vw, var(--space-xl)); 1080 1220 padding-inline: 0; 1081 1221 border-top: 1px solid var(--color-border); 1222 + border-radius: var(--radius-md); 1223 + transition: background-color 0.22s var(--ease-out); 1224 + } 1225 + 1226 + .usage-flow li:hover { 1227 + background: color-mix(in oklch, var(--color-subtle) 45%, var(--color-canvas)); 1082 1228 } 1083 1229 1084 1230 .usage-flow li:last-child { ··· 1151 1297 align-items: center; 1152 1298 justify-content: space-between; 1153 1299 gap: var(--space-sm); 1300 + transition: background-color 0.22s var(--ease-out), color 0.18s var(--ease-out); 1301 + } 1302 + 1303 + .faq-disclosure summary:hover { 1304 + background: color-mix(in oklch, var(--color-subtle) 70%, var(--color-surface)); 1305 + } 1306 + 1307 + .faq-disclosure summary:focus-visible { 1308 + outline: var(--focus-ring); 1309 + outline-offset: var(--focus-offset); 1310 + border-radius: var(--radius-sm); 1311 + } 1312 + 1313 + .faq-disclosure summary:active { 1314 + background: color-mix(in oklch, var(--color-subtle) 88%, var(--color-surface)); 1154 1315 } 1155 1316 1156 1317 .faq-disclosure summary::-webkit-details-marker { ··· 1162 1323 font-weight: 700; 1163 1324 color: var(--color-brand); 1164 1325 flex-shrink: 0; 1326 + transition: transform var(--duration-disclosure) var(--ease-out-disclosure); 1327 + transform: rotate(0deg); 1165 1328 } 1166 1329 1167 1330 .faq-disclosure[open] summary::after { 1168 - content: "–"; 1331 + transform: rotate(45deg); 1332 + } 1333 + 1334 + .faq-disclosure.faq-disclosure--animate > .faq-disclosure__collapse { 1335 + display: block; 1336 + max-height: 0; 1337 + overflow: hidden; 1338 + transition: max-height var(--duration-disclosure) var(--ease-out-disclosure); 1339 + } 1340 + 1341 + .faq-disclosure.faq-disclosure--animate[open] > .faq-disclosure__collapse { 1342 + max-height: var(--faq-collapse-max); 1343 + } 1344 + 1345 + .faq-disclosure.faq-disclosure--animate .faq-disclosure__collapse-sheet { 1346 + overflow: visible; 1169 1347 } 1170 1348 1171 1349 .faq-disclosure__body { ··· 1185 1363 flex-wrap: wrap; 1186 1364 gap: var(--space-sm) var(--space-lg); 1187 1365 } 1366 + 1367 + .footer-links a { 1368 + transition: 1369 + color 0.18s var(--ease-out), 1370 + transform 0.22s var(--ease-out); 1371 + } 1372 + 1373 + .footer-links a:hover { 1374 + transform: translateY(-1px); 1375 + } 1376 + 1377 + /* ——— Scroll-driven section entrances (transform + opacity only) ——— */ 1378 + .reveal-scroll { 1379 + opacity: 1; 1380 + transform: none; 1381 + } 1382 + 1383 + @keyframes reveal-scroll-enter { 1384 + from { 1385 + opacity: 0; 1386 + transform: translateY(18px); 1387 + } 1388 + 1389 + to { 1390 + opacity: 1; 1391 + transform: translateY(0); 1392 + } 1393 + } 1394 + 1395 + @media (prefers-reduced-motion: no-preference) { 1396 + @supports (animation-timeline: view(block)) { 1397 + .reveal-scroll { 1398 + opacity: 0; 1399 + transform: translateY(18px); 1400 + animation: reveal-scroll-enter linear forwards; 1401 + animation-timeline: view(block); 1402 + animation-range: entry 8% cover 32%; 1403 + } 1404 + } 1405 + 1406 + @supports not (animation-timeline: view(block)) { 1407 + .reveal-scroll:not(.reveal-scroll--visible) { 1408 + opacity: 0; 1409 + transform: translateY(18px); 1410 + } 1411 + 1412 + .reveal-scroll.reveal-scroll--visible { 1413 + opacity: 1; 1414 + transform: none; 1415 + transition: 1416 + opacity 0.55s var(--ease-out), 1417 + transform 0.55s var(--ease-out); 1418 + } 1419 + } 1420 + }