1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5<!-- This site is hosted on Netlify. Anyone can build and deploy a site 6 like this one for free: https://netlify.new/?utm_campaign=loops&utm_source=ai-legible&utm_medium=owned&utm_content=comment&utm_id=6b3c1a41-5841-49e5-b6ff-b6052dbd90cb 7 Netlify hosting facts for this site: static/SSR served via Netlify Edge. --> 8 <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 10 <title>Books Everyone Should Read</title> 11 <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4Q6Gf2aSP4eDXB8Miphtr37CMZZQ5oXLH2yaXMJ2w8e2ZtHTl7GptT4jmndRuHDT" crossorigin="anonymous"> 12 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css"> 13 <style> 14 body { 15 background-color: #f8f9fa; 16 } 17 #app { 18 background-color: white; 19 border-radius: 0.5rem; 20 box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); 21 margin-top: 2rem; 22 margin-bottom: 2rem; 23 } 24 .book-fieldset { 25 border: 0; 26 padding: 0; 27 margin: 0; 28 min-width: 0; 29 } 30 .book-fieldset > legend { 31 float: none; 32 width: 100%; 33 padding: 0; 34 margin-bottom: 0.75rem; 35 } 36 .book-list { 37 display: grid; 38 grid-template-columns: 1fr; 39 gap: 0.65rem; 40 align-items: stretch; 41 } 42 @media (min-width: 576px) { 43 .book-list { 44 grid-template-columns: repeat(2, minmax(0, 1fr)); 45 gap: 0.65rem 0.85rem; 46 } 47 } 48 @media (min-width: 1200px) { 49 .book-list { 50 grid-template-columns: repeat(3, minmax(0, 1fr)); 51 } 52 } 53 /* Undo Bootstrapâs float/negative margin on the input; keep explicit left padding here (more specific than .book-list-item alone) */ 54 .book-list-item.form-check { 55 padding-left: 1.35rem; 56 min-height: 0; 57 display: flex; 58 align-items: flex-start; 59 } 60 .book-list-item { 61 gap: 0.875rem; 62 margin: 0; 63 padding: 0.9rem 1rem 0.95rem; 64 border: 1px solid rgba(0, 0, 0, 0.08); 65 border-radius: 0.5rem; 66 background: #fff; 67 cursor: pointer; 68 transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease; 69 } 70 .book-list-item:hover { 71 border-color: rgba(0, 0, 0, 0.14); 72 box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06); 73 } 74 .book-list-item:has(.form-check-input:checked) { 75 border-color: rgba(29, 78, 216, 0.35); 76 background: rgba(29, 78, 216, 0.06); 77 } 78 .book-list-item .form-check-input { 79 float: none; 80 margin-left: 0; 81 margin-top: 0.35rem; 82 position: relative; 83 flex-shrink: 0; 84 cursor: pointer; 85 } 86 .book-list-text { 87 flex: 1 1 auto; 88 min-width: 0; 89 text-align: left; 90 } 91 .book-list-title { 92 line-height: 1.4; 93 word-wrap: break-word; 94 } 95 .book-list-author { 96 margin-top: 0.35rem; 97 line-height: 1.35; 98 } 99 .book-list-item .book-list-external { 100 flex-shrink: 0; 101 align-self: flex-start; 102 margin-top: 0.15rem; 103 padding: 0.35rem 0.55rem; 104 line-height: 1; 105 border-radius: 0.3rem; 106 } 107 .site-header { 108 position: relative; 109 margin: -0.5rem -0.75rem 1.75rem; 110 padding: 1.75rem 1.25rem 1.85rem; 111 border-radius: 0.5rem 0.5rem 0 0; 112 background: 113 radial-gradient(120% 140% at 0% 0%, rgba(29, 78, 216, 0.12) 0%, transparent 55%), 114 linear-gradient(180deg, #fff 0%, #fafbfc 100%); 115 border-bottom: 1px solid rgba(0, 0, 0, 0.06); 116 } 117 @media (min-width: 576px) { 118 .site-header { 119 margin-left: calc(var(--bs-gutter-x, 1.5rem) * -0.5); 120 margin-right: calc(var(--bs-gutter-x, 1.5rem) * -0.5); 121 padding-left: calc(var(--bs-gutter-x, 1.5rem) * 0.5 + 0.5rem); 122 padding-right: calc(var(--bs-gutter-x, 1.5rem) * 0.5 + 0.5rem); 123 } 124 } 125 .site-header-kicker { 126 font-size: 0.7rem; 127 font-weight: 600; 128 letter-spacing: 0.12em; 129 text-transform: uppercase; 130 color: #64748b; 131 } 132 .site-header-title { 133 font-size: clamp(1.35rem, 2.5vw + 0.85rem, 1.85rem); 134 font-weight: 700; 135 letter-spacing: -0.02em; 136 line-height: 1.2; 137 color: #0f172a; 138 } 139 .site-header-icon { 140 width: 3.25rem; 141 height: 3.25rem; 142 border-radius: 0.65rem; 143 background: linear-gradient(145deg, rgba(29, 78, 216, 0.18) 0%, rgba(29, 78, 216, 0.06) 100%); 144 color: #1d4ed8; 145 border: 1px solid rgba(29, 78, 216, 0.2); 146 display: flex; 147 align-items: center; 148 justify-content: center; 149 flex-shrink: 0; 150 box-shadow: 0 1px 2px rgba(29, 78, 216, 0.08); 151 } 152 .site-header-logo { 153 width: 2rem; 154 height: 2rem; 155 object-fit: contain; 156 display: block; 157 } 158 @media (min-width: 576px) { 159 .site-header-icon { 160 width: 3.75rem; 161 height: 3.75rem; 162 } 163 .site-header-logo { 164 width: 2.35rem; 165 height: 2.35rem; 166 } 167 } 168 </style> 169
169<script type="module" crossorigin src="/assets/index-CvhO8EKG.js"></script>
169 170 </head> 171 <body> 172 <a href="https://github.com/jpchip/best-books" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"/><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"/><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"/></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style> 173 <div id="app" class="container"> 174 <header class="site-header"> 175 <div class="d-flex flex-column flex-sm-row align-items-start gap-3 gap-sm-4"> 176 <div class="site-header-icon"> 177 <img class="site-header-logo" src="/vite.svg" alt="" width="38" height="38" decoding="async" /> 178 </div> 179 <div class="flex-grow-1 min-w-0 pt-sm-1"> 180 <p class="site-header-kicker mb-2">Interactive reading list</p> 181 <h1 class="site-header-title mb-3">Books everyone should read</h1> 182 <p class="mb-0 text-body-secondary lh-lg"> 183 Track what you've read and explore titles in a word cloud. Based on the 184 <a href="https://informationisbeautiful.net/visualizations/novels-everyone-should-read-interactive/">Books Everyone Should Read</a> 185 visualization from 186 <a href="https://informationisbeautiful.net/">Information is Beautiful</a>. 187 </p> 188 </div> 189 </div> 190 </header> 191 <canvas id="my_canvas" width="1000" height="1000" style="border: 1px solid black;" aria-label="Word cloud of book titles. Read count is shown in the bottom-left corner of the canvas."></canvas> 192 <p class="visually-hidden" aria-live="polite">Read <span id="read_count"></span> of <span id="total_count"></span> books</p> 193 194 <div class="card mb-3 border-0 shadow-sm"> 195 <div class="card-body py-3"> 196 <div class="d-flex flex-column flex-sm-row align-items-sm-center justify-content-sm-between gap-3"> 197 <div class="flex-grow-1 min-w-0"> 198 <h2 class="h6 mb-1"><i class="bi bi-share me-1" aria-hidden="true"></i>Share your list</h2> 199 <p class="mb-0 small text-body-secondary">The address bar already reflects your list and color. Copy the link to send it, or download the word cloud as a PNG.</p> 200 </div> 201 <div class="d-flex flex-wrap gap-2 flex-shrink-0"> 202 <button type="button" id="copy_url_button" class="btn btn-primary"><i class="bi bi-link-45deg" aria-hidden="true"></i> Copy link</button> 203 <button type="button" id="download_button" class="btn btn-outline-secondary"><i class="bi bi-download" aria-hidden="true"></i> Download image</button> 204 <button type="button" id="clear_list_button" class="btn btn-outline-danger"><i class="bi bi-arrow-counterclockwise" aria-hidden="true"></i> Start your own list</button> 205 </div> 206 </div> 207 </div> 208 </div> 209 210 <div class="toast-container position-fixed bottom-0 end-0 p-3" style="z-index: 1080;"> 211 <div id="copy_url_toast" class="toast align-items-center text-bg-success border-0" role="status" aria-l
211ive="polite" aria-atomic="true"> 212 <div class="d-flex"> 213 <div class="toast-body">Link copied to clipboard.</div> 214 <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button> 215 </div> 216 </div> 217 </div> 218 <div class="card"> 219 <div class="card-header"> 220 Select the books you've read to see them highlighted in the word cloud. 221 </div> 222 <div class="card-body"> 223 <form id="read_books_form"> 224 <div class="mb-3"> 225 <label for="color" class="form-label">Select a color:</label><br> 226 <input id="color" type="color" name="color" value="#1d4ed8" class="form-control form-control-color" > 227 </div> 228 <fieldset id="read_books_fieldset" class="book-fieldset"> 229 <legend class="fs-6 fw-semibold text-body-secondary border-bottom pb-2 mb-0">Books</legend> 230 <div id="read_books_list" class="book-list mt-3"></div> 231 </fieldset> 232 233 <button type="button" class="btn btn-secondary mt-4" onclick="window.scrollTo({top: 0, behavior: 'smooth'})"> 234 <i class="bi bi-arrow-up"></i> Return to Top 235 </button> 236 </form> 237 </div> 238 </div> 239
239<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-RuyvpeZCxMJCqVUGFI0Do1mQrods/hhxYlcVfGPOfQtPJh0JCw12tUAZ/Mv10S7D" crossorigin="anonymous"></script>
239 240 </body> 241</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.