1/** 2 * WebNotePad â sidebar.js 3 * Injects a fixed dynamic sidebar for the 15 productive tools 4 * Theme: Editorial / Ink-on-paper aesthetic 5 * Updated: Category-wise organization with attention-grabbing pulsing trigger 6 * + 300x250 banner ad slot at the top of the sidebar 7 * + 2-column grid layout for tools 8 */ 9 10(function () { 11 // 1. Array list of tools organized by categories 12 const categories = [ 13 { 14 name: "ð Writing & Note-Taking", 15 tools: [ 16 { name: "Notepad", icon: "ð", url: "/#notepad", desc: "Write, edit and auto-save notes instantly." }, 17 { name: "Diary", icon: "ð", url: "/diary", desc: "Keep a private daily journal with dated entries." }, 18 { name: "Focus Writer", icon: "ð¯", url: "/focus-writer", desc: "Minimalist writing mode with a zen focus." }, 19 { name: "Typing Test", icon: "â¨ï¸", url: "/typing-test", desc: "Test your typing speed and accuracy in WPM." }, 20 { name: "WordPad", icon: "ð", url: "/wordpad-online", desc: "Rich text editor with fonts, colors, and export." } 21 ] 22 }, 23 { 24 name: "ð Text Analysis & Manipulation", 25 tools: [ 26 { name: "Case Converter", icon: "ð¤", url: "/case-converter", desc: "Transform text to uppercase, lowercase, etc." }, 27 { name: "Word Counter", icon: "ð", url: "/word-counter", desc: "Count words, characters, and sentences." }, 28 { name: "Readability Analyzer", icon: "ð", url: "/readability", desc: "Check reading ease and complexity scores." }, 29 { name: "Word Shuffler", icon: "ð", url: "/word-shuffler", desc: "Randomize word order in any text." }, 30 { name: "Special Character Converter", icon: "ð¤", url: "/special-character-converter", desc: "Convert umlauts, diacritics, and special characters." } 31 ] 32 }, 33 { 34 name: "ð§ Idea Organization & Visualization", 35 tools: [ 36 { name: "MindMap", icon: "ð§ ", url: "/mindmap", desc: "Visualize ideas and brainstorm interactively." }, 37 { name: "List Maker", icon: "â ", url: "/list-maker", desc: "Create checklists and to-dos with ease." } 38 ] 39 }, 40 { 41 name: "ð² Creativity & Randomization", 42 tools: [ 43 44 { name: "Random Text", icon: "ð²", url: "/random-text", desc: "Generate placeholder paragraphs or words." }, 45 { name: "Word Cloud Generator", icon: "âï¸", url: "/word-cloud", desc: "Turn text into a beautiful visual word cloud." }, 46 { name: "Decision Maker", icon: "âï¸", url: "/choice-maker", desc: "Spin a wheel or flip a coin to decide." }, 47 { name: "Random Name Generator", icon: "ð¤", url: "/random-name-generator", desc: "Generate random first, last, and full names." } 48 ] 49 }, 50 { 51 name: "ð Word & Puzzle Helpers", 52 tools: [ 53 { name: "Word Finder", icon: "ð", url: "/word-finder", desc: "Find words, solve anagrams, and discover terms." }, 54 { name: "Crossword Solver", icon: "ð ", url: "/crossword-solver", desc: "Clue helper, word finder, and puzzle help." }, 55 { name: "Word Search Solver", icon: "ðµð»", url: "/word-search-solver", desc: "Word search solver, and word puzzle solver." } 56 ] 57 }, 58 { 59 name: "â³ Productivity & Habit Management", 60 tools: [ 61 { name: "Pomodoro Timer", icon: "ð ", url: "/pomodoro-timer", desc: "Stay focused with customizable intervals." }, 62 { name: "Habit Tracker", icon: "ð ", url: "/habit-tracker", desc: "Build streaks and track daily habits." } 63 ] 64 }, 65 { 66 name: "ð Fun & Utilities", 67 tools: [ 68 { name: "Emoji Picker", icon: "ð", url: "/emoji-picker", desc: "Pick emojis, and copy emojis." } 69 ] 70 } 71 ]; 72 73 // Flatten tools for any potential use 74 const allTools = categories.flatMap(cat => cat.tools); 75 76 // 2. Inject CSS Styles with category enhancements and pulsing keyframes 77 const cssStyles = ` 78 /* Floating Launch Trigger Button */ 79 .tools-floating-trigger { 80 position: fixed; 81 bottom: 120px; 82 right: 24px; 83 z-index: 9999; 84 width: 52px; 85 height: 52px; 86 background: var(--ink); 87 color: var(--paper); 88 border-radius: 50%; 89 display: flex; 90 align-items: center; 91 justify-content: center; 92 font-size: 1.4rem; 93 box-shadow: var(--shadow); 94 cursor: pointer; 95 border: 1px solid var(--paper-edge); 96 transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), background 0.2s ease, color 0.2s ease, box-shadow 0.3s ease; 97 98 /* Attention Grabber Pulse */ 99 animation: attentionPulse 2.5s infinite cubic-bezier(0.4, 0, 0.2, 1); 100 } 101 body.dark .tools-floating-trigger { 102 background: var(--accent); 103 color: var(--white); 104 } 105 .tools-floating-trigger:hover { 106 transform: scale(1.08) rotate(15deg); 107 background: var(--accent); 108 color: var(--white); 109 animation-play-state: paused; /* Pause pulsing while user hovers */ 110 box-shadow: 0 8px 24px rgba(196, 86, 42, 0.3); 111 } 112 .tools-floating-trigger.active { 113 transform: scale(0.9) rotate(-90deg); 114 background: var(--paper-warm); 115 color: var(--ink); 116 animation: none; /* Kill animation when the sidebar is open */ 117 box-shadow: none; 118 } 119 120 /* Fixed Sidebar Layout Container */ 121 .tools-fixed-sidebar { 122 position: fixed; 123 top: 0; 124 right: -340px; 125 width: 320px; 126 height: 100vh; 127 background: var(--paper); 128 border-left: 1px solid var(--paper-edge); 129 box-shadow: var(--shadow-lg); 130 z-index: 10000; 131 display: flex; 132 flex-direction: column; 133 transition: right 0.4s cubic-bezier(0.4, 0, 0.2, 1); 134 } 135 .tools-fixed-sidebar.open { 136 right: 0; 137 } 138
139 /* Dimmed Background Backdrop Overlay */ 140 .tools-sidebar-overlay { 141 position: fixed; 142 top: 0; 143 left: 0; 144 width: 100vw; 145 height: 100vh; 146 background: rgba(26, 26, 46, 0.4); 147 backdrop-filter: blur(4px); 148 z-index: 9999; 149 opacity: 0; 150 pointer-events: none; 151 transition: opacity 0.3s ease; 152 } 153 body.dark .tools-sidebar-overlay { 154 background: rgba(0, 0, 0, 0.6); 155 } 156 .tools-sidebar-overlay.visible { 157 opacity: 1; 158 pointer-events: auto; 159 } 160 161 /* Sidebar Header Details */ 162 .tools-sb-header { 163 padding: 20px 24px; 164 border-bottom: 1px solid var(--paper-edge); 165 display: flex; 166 align-items: center; 167 justify-content: space-between; 168 background: var(--paper-warm); 169 flex-shrink: 0; 170 } 171 .tools-sb-header h2 { 172 font-family: var(--font-display); 173 font-size: 1.25rem; 174 font-weight: 700; 175 color: var(--ink); 176 } 177 .tools-sb-header h2 em { 178 font-style: italic; 179 color: var(--accent); 180 } 181 .tools-sb-close { 182 width: 32px; 183 height: 32px; 184 font-size: 1rem; 185 color: var(--ink-muted); 186 border-radius: var(--radius); 187 display: flex; 188 align-items: center; 189 justify-content: center; 190 cursor: pointer; 191 transition: all var(--transition); 192 background: none; 193 border: none; 194 } 195 .tools-sb-close:hover { 196 color: var(--ink); 197 background: var(--paper-edge); 198 } 199 200 /* ---- Ad Slot (300x250) ---- */ 201 .tools-sb-ad { 202 flex-shrink: 0; 203 padding: 14px 16px 10px; 204 border-bottom: 1px solid var(--paper-edge); 205 background: var(--paper); 206 display: flex; 207 flex-direction: column; 208 align-items: center; 209 gap: 6px; 210 } 211 .tools-sb-ad-label { 212 font-family: var(--font-display); 213 font-size: 0.6rem; 214 font-weight: 700; 215 letter-spacing: 0.12em; 216 text-transform: uppercase; 217 color: var(--ink-muted); 218 opacity: 0.55; 219 align-self: flex-start; 220 } 221 .tools-sb-ad-frame { 222 width: 300px; 223 max-width: 100%; 224 height: 250px; 225 display: flex; 226 align-items: center; 227 justify-content: center; 228 overflow: hidden; 229 border-radius: var(--radius); 230 background: var(--paper-warm); 231 border: 1px solid var(--paper-edge); 232 } 233 .tools-sb-ad-frame iframe, 234 .tools-sb-ad-frame img, 235 .tools-sb-ad-frame > div { 236 max-width: 100%; 237 border: 0; 238 display: block; 239 } 240 241 /* Scrollable items menu wrapper â 2 columns */ 242 .tools-sb-body { 243 flex: 1; 244 overflow-y: auto; 245 padding: 12px 16px 24px; 246 display: grid; 247 grid-template-columns: 1fr 1fr; 248 gap: 8px; 249 align-content: start; 250 } 251 252 /* Category Section Headers â span both columns */ 253 .tools-sb-category { 254 grid-column: 1 / -1; 255 font-family: var(--font-display); 256 font-size: 0.68rem; 257 font-weight: 700; 258 text-transform: uppercase; 259 letter-spacing: 0.06em; 260 color: var(--ink-muted); 261 padding: 14px 4px 6px 4px; 262 border-bottom: 1px solid var(--paper-edge); 263 margin-top: 4px; 264 opacity: 0.7; 265 } 266 .tools-sb-category:first-of-type { 267 padding-top: 6px; 268 } 269 270 /* Category item count badge */ 271 .tools-sb-category-count { 272 font-size: 0.6rem; 273 font-weight: 400; 274 color: var(--ink-muted); 275 opacity: 0.5; 276 margin-left: 6px; 277 } 278 279 /* Single Tool Items Card â compact for 2-column grid */ 280 .tools-sb-item { 281 display: flex; 282 flex-direction: column; 283 align-items: center; 284 text-align: center; 285 gap: 8px; 286 padding: 14px 8px 12px; 287 border-radius: var(--radius); 288 border: 1px solid var(--paper-edge); 289 background: var(--paper-warm); 290 transition: all var(--transition); 291 opacity: 0; 292 transform: translateY(10px); 293 text-decoration: none; 294 cursor: pointer; 295 min-width: 0; 296 } 297 .tools-fixed-sidebar.open .tools-sb-item { 298 animation: slideInItem 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards; 299 } 300 .tools-sb-item:hover { 301 background: var(--paper); 302 border-color: var(--accent); 303 transform: translateY(-2px); 304 box-shadow: var(--shadow-sm); 305 } 306 .tools-sb-item-icon { 307 font-size: 1.4rem; 308 width: 40px; 309 height: 40px; 310 background: var(--paper); 311 border-radius: var(--radius); 312 display: flex; 313 align-items: center; 314 justify-content: center; 315 border: 1px solid var(--paper-edge); 316 transition: background var(--transition), border-color var(--transition); 317 flex-shrink: 0; 318 } 319 .tools-sb-item:hover .tools-sb-item-icon { 320 background: var(--accent-pale); 321 border-color: var(--accent); 322 } 323 body.dark .tools-sb-item:hover .tools-sb-item-icon { 324 background: rgba(196,86,42,0.15); 325 } 326 .tools-sb-item-details { 327 flex: 1; 328 min-width: 0; 329 width: 100%; 330 } 331 .tools-sb-item-name { 332 font-size: 0.78rem; 333 font-weight: 600; 334 color: var(--ink); 335 margin-bottom: 2px; 336 line-height: 1.2; 337 word-break: break-word; 338 } 339 .tools-sb-item-desc { 340 font-size: 0.65rem; 341 color: var(--ink-muted); 342 line-height: 1.25; 343 display: -webkit-box; 344 -webkit-line-clamp: 2; 345 -webkit-box-orient: vertical; 346 overflow: hidden; 347 } 348 349 /* Scrollbar styling */ 350 .tools-sb-body::-webkit-scrollbar {
351 width: 4px; 352 } 353 .tools-sb-body::-webkit-scrollbar-track { 354 background: transparent; 355 } 356 .tools-sb-body::-webkit-scrollbar-thumb { 357 background: var(--paper-edge); 358 border-radius: 4px; 359 } 360 361 /* Keyframe Animations */ 362 @keyframes slideInItem { 363 to { 364 opacity: 1; 365 transform: translateY(0); 366 } 367 } 368 369 /* Elegant, Organic Attention Pulse Animation */ 370 @keyframes attentionPulse { 371 0% { 372 transform: scale(1); 373 box-shadow: 0 0 0 0 rgba(196, 86, 42, 0.4), var(--shadow); 374 } 375 50% { 376 transform: scale(1.08); 377 box-shadow: 0 0 0 12px rgba(196, 86, 42, 0), var(--shadow); 378 } 379 100% { 380 transform: scale(1); 381 box-shadow: 0 0 0 0 rgba(196, 86, 42, 0), var(--shadow); 382 } 383 } 384 385 /* Responsive adjustments */ 386 @media (max-width: 480px) { 387 .tools-fixed-sidebar { 388 width: 100%; 389 right: -100%; 390 } 391 .tools-fixed-sidebar.open { 392 right: 0; 393 } 394 .tools-sb-header h2 { 395 font-size: 1rem; 396 } 397 .tools-sb-body { 398 padding: 10px 12px 20px; 399 gap: 6px; 400 } 401 .tools-sb-item { 402 padding: 10px 6px 8px; 403 gap: 6px; 404 } 405 .tools-sb-item-icon { 406 width: 34px; 407 height: 34px; 408 font-size: 1.2rem; 409 } 410 .tools-sb-item-name { 411 font-size: 0.72rem; 412 } 413 .tools-sb-item-desc { 414 font-size: 0.6rem; 415 } 416 .tools-sb-ad { 417 padding: 12px 10px 8px; 418 } 419 .tools-sb-ad-frame { 420 height: auto; 421 min-height: 250px; 422 } 423 } 424 `; 425 426 // 3. Inject styles into document head 427 const styleEl = document.createElement("style"); 428 styleEl.textContent = cssStyles; 429 document.head.appendChild(styleEl); 430 431 // 4. Generate the complete DOM structural markup dynamically 432 const rootContainer = document.getElementById("tools-sidebar-root"); 433 if (!rootContainer) return; 434 435 // Render the floating toggle switch, backdrop container, sidebar dashboard, and ad slot 436 rootContainer.innerHTML = ` 437 <div class="tools-sidebar-overlay" id="toolsSidebarOverlay"></div> 438 <div class="tools-floating-trigger" id="toolsSidebarTrigger" title="Explore Toolkit" aria-label="Toggle structural toolkit">ð§°</div> 439 <aside class="tools-fixed-sidebar" id="toolsFixedSidebar" aria-label="WebNotepad Toolkit Sidebar"> 440 <div class="tools-sb-header"> 441 <h2>WebNotepad <em>Toolkit</em></h2> 442 <button class="tools-sb-close" id="toolsSidebarClose" aria-label="Close toolkit">â</button> 443 </div> 444 445 <!-- 300x250 Banner Ad Slot --> 446 <div class="tools-sb-ad" id="toolsSidebarAd"> 447 <span class="tools-sb-ad-label">Advertisement</span> 448 <div class="tools-sb-ad-frame" id="toolsSidebarAdFrame"></div> 449 </div> 450 451 <div class="tools-sb-body" id="toolsSidebarBody"></div> 452 </aside> 453 `; 454 455 const sidebarBody = document.getElementById("toolsSidebarBody"); 456 const sidebar = document.getElementById("toolsFixedSidebar"); 457 const trigger = document.getElementById("toolsSidebarTrigger"); 458 const overlay = document.getElementById("toolsSidebarOverlay"); 459 const closeBtn = document.getElementById("toolsSidebarClose"); 460 const adFrame = document.getElementById("toolsSidebarAdFrame"); 461 462 // 4a. Inject the 300x250 ad scripts into the ad frame. 463 // We append the config + external invoke script into the ad frame container. 464 // The external script writes its iframe to the element it is placed in, 465 // so we place it directly inside the ad frame wrapper. 466 (function injectAd() { 467 if (!adFrame) return; 468 469 // Inline atOptions configuration (must run before the invoke script loads) 470 const configScript = document.createElement("script"); 471 configScript.type = "text/javascript"; 472 configScript.text = ` 473 atOptions = { 474 'key' : 'f5214acd8479e07d7defe4626c574aa5', 475 'format' : 'iframe', 476 'height' : 250, 477 'width' : 300, 478 'params' : {} 479 }; 480 `; 481 adFrame.appendChild(configScript); 482 483 // External invoke script 484 const invokeScript = document.createElement("script"); 485 invokeScript.type = "text/javascript"; 486 invokeScript.src = "https://www.highrevenueformat.com/f5214acd8479e07d7defe462
4866c574aa5/invoke.js"; 487 invokeScript.async = true; 488 adFrame.appendChild(invokeScript); 489 })(); 490 491 // 5. Populate list items with categories and staggered animations 492 let toolIndex = 0; 493 494 categories.forEach((category) => { 495 // Add category header 496 const catHeader = document.createElement("div"); 497 catHeader.className = "tools-sb-category"; 498 catHeader.textContent = category.name; 499 sidebarBody.appendChild(catHeader); 500 501 // Add tools under this category 502 category.tools.forEach((tool) => { 503 const item = document.createElement("a"); 504 item.href = tool.url; 505 item.className = "tools-sb-item"; 506 item.style.animationDelay = `${toolIndex * 0.025}s`; 507 508 item.innerHTML = ` 509 <div class="tools-sb-item-icon">${tool.icon}</div> 510 <div class="tools-sb-item-details"> 511 <div class="tools-sb-item-name">${tool.name}</div> 512 <div class="tools-sb-item-desc">${tool.desc}</div> 513 </div> 514 `; 515 sidebarBody.appendChild(item); 516 toolIndex++; 517 }); 518 }); 519 520 // 6. Active Structural Interface Controls and Handlers 521 function toggleSidebar() { 522 const isOpen = sidebar.classList.toggle("open"); 523 trigger.classList.toggle("active", isOpen); 524 overlay.classList.toggle("visible", isOpen); 525 trigger.innerHTML = isOpen ? "â" : "ð§°"; 526 527 // Re-trigger animations when opening 528 if (isOpen) { 529 const items = sidebarBody.querySelectorAll(".tools-sb-item"); 530 items.forEach((item, idx) => { 531 item.style.animation = "none"; 532 item.offsetHeight; // trigger reflow 533 item.style.animation = `slideInItem 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards`; 534 item.style.animationDelay = `${idx * 0.025}s`; 535 }); 536 } 537 } 538 539 function closeSidebar() { 540 sidebar.classList.remove("open"); 541 trigger.classList.remove("active"); 542 overlay.classList.remove("visible"); 543 trigger.innerHTML = "ð§°"; 544 } 545 546 // Bind Listeners 547 trigger.addEventListener("click", toggleSidebar); 548 overlay.addEventListener("click", closeSidebar); 549 closeBtn.addEventListener("click", closeSidebar); 550 551 // Close interface gracefully via the Escape key 552 window.addEventListener("keydown", (e) => { 553 if (e.key === "Escape") closeSidebar(); 554 }); 555})();
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.