1// Hero Component - Reusable hero section for SchoolBlocks 2// Based on the provided design with blue theme and mobile responsiveness 3 4class HeroComponent { 5 constructor(config = {}) { 6 this.config = { 7 title: config.title || "#1 Google Workspace", 8 subtitle: config.subtitle || "Integrated Provider", 9 description: config.description || "SchoolBlocks is your trusted Google Workspace integrated provider. We seamlessly sync users, calendars, files, and Google Classroom to create a unified digital experience. Keep your website content automatically updated with your Google services while maintaining security and proper permissions.", 10 ctaText: config.ctaText || "EXPLORE INTEGRATION", 11 ctaUrl: config.ctaUrl || "get-started.html", 12 heroImage: config.heroImage || "Photos/Images/google/google-integration-hero-vector.png", 13 showPartners: config.showPartners || false, 14 backgroundColor: config.backgroundColor || "#E8F4FD", // Light blue background 15 ...config 16 }; 17 } 18 19 // Generate the CSS styles for the hero component 20 generateStyles() { 21 return ` 22 <style> 23 .hero-component { 24 background: linear-gradient(135deg, #E8F4FD 0%, #F0F8FF 50%, #E8F4FD 100%); 25 min-height: calc(100vh - 80px); /* Account for navbar */ 26 display: flex; 27 align-items: center; 28 position: relative; 29 overflow: visible; 30 padding: 20px 0; 31 } 32 33 .hero-component::before { 34 content: ''; 35 position: absolute; 36 top: 0; 37 left: 0; 38 right: 0; 39 bottom: 0; 40 background: 41 radial-gradient(circle at 20% 80%, rgba(74, 144, 226, 0.1) 0%, transparent 50%), 42 radial-gradient(circle at 80% 20%, rgba(78, 205, 196, 0.1) 0%, transparent 50%); 43 z-index: 1; 44 } 45 46 .hero-container { 47 width: 100%; 48 max-width: 1600px; 49 margin: 0 auto; 50 padding: 0 40px; 51 position: relative; 52 z-index: 10; 53 display: flex; 54 flex-direction: column; 55 min-height: 600px; 56 gap: 15px; 57 } 58 59 .hero-main { 60 display: grid; 61 grid-template-columns: 50% 50%; 62 align-items: center; 63 gap: 0; 64 min-height: 450px; 65 padding: 20px 0; 66 max-width: 1600px; 67 margin: 0 auto; 68 width: 100%; 69 } 70 71 .hero-content { 72 display: flex; 73 flex-direction: column; 74 justify-content: center; 75 align-items: flex-start; 76 text-align: left; 77 padding-right: 40px; 78 width: 100%; 79 box-sizing: border-box; 80 } 81 82 .hero-visual { 83 display: flex; 84 align-items: center; 85 justify-content: center; 86 position: relative; 87 padding-left: 40px; 88 width: 100%; 89 box-sizing: border-box; 90 } 91 92 .hero-title { 93 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; 94 font-size: clamp(2.6rem, 4.2vw, 3.6rem); 95 font-weight: 700; 96 color: #2C3E50; 97 margin-bottom: 0.5rem; 98 line-height: 1.1; 99 letter-spacing: -0.02em; 100 white-space: nowrap; 101 } 102 103 .hero-subtitle { 104 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; 105 font-size: clamp(2.34rem, 3.9vw, 3.25rem); 106 font-weight: 600; 107 color: #4A90E2; 108 margin-bottom: 1.5rem; 109 line-height: 1.2; 110 white-space: nowrap; 111 } 112 113 .hero-description { 114 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; 115 font-size: clamp(1.3rem, 1.56vw, 1.56rem); 116 line-height: 1.6; 117 color: #5A6C7D; 118 margin-bottom: 2rem; 119 max-width: 95%; 120 } 121 122 .hero-cta { 123 margin-bottom: 0; 124 } 125 126 .hero-cta-btn { 127 background: #4A90E2; 128 color: white; 129 padding: 18px 40px; 130 border-radius: 50px; 131 text-decoration: none; 132 font-weight: 600; 133 font-size: 1.1rem; 134 display: inline-block; 135 transition: all 0.3s ease; 136 border: none; 137 cursor: pointer; 138 letter-spacing: 0.5px; 139 text-transform: uppercase; 140 box-shadow: 0 4px 20px rgba(74, 144, 226, 0.3); 141 } 142 143 .hero-cta-btn:hover { 144 background: #357ABD; 145 transform: translateY(-2px); 146 box-shadow: 0 8px 30px rgba(74, 144, 226, 0.4); 147 text-decoration: none; 148 color: white; 149 } 150 151 .hero-image-container { 152 width: 100%; 153 height: 500px; 154 display: flex; 155 align-items: center; 156 justify-content: center; 157 position: relative; 158 } 159 160 .hero-image { 161 width: 100%; 162 height: 100%; 163 object-fit: contain; 164 border-radius: 20px; 165 filter: drop-shadow(0 20px 40px rgba(0, 0, 0, 0.1)); 166 max-width: 100%; 167 } 168 169 .hero-partners { 170 padding: 0 0 10px 0; 171 display: flex; 172 justify-content: center; 173 align-items: center; 174 gap: 30px; 175 flex-wrap: wrap; 176 flex-shrink: 0; 177 } 178 179 .partner-btn { 180 display: flex; 181 align-items: center; 182 justify-content: center; 183 gap: 12px; 184 padding: 14px 24px; 185 background: rgba(255, 255, 255, 0.9); 186 border: 1px solid rgba(74, 144, 226, 0.2); 187 border-radius: 50px; 188 text-decoration: none; 189 color: #5A6C7D; 190 font-size: 0.9rem; 191 font-weight: 500; 192 transition: all 0.3s ease; 193 box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); 194 backdrop-filter: blur(10px); 195 min-width: 220px; 196 height: 52px; 197 text-align: center; 198 position: relative; 199 overflow: hidden; 200 } 201 202 .partner-btn::before { 203 content: ''; 204 position: absolute; 205 top: 0; 206 left: -100%; 207 width: 100%; 208 height: 100%; 209 background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent); 210 transition: left 0.5s ease; 211 z-index: 1; 212 } 213 214 .partner-btn:hover::before { 215 left: 100%; 216 } 217 218 .partner-btn > * { 219 position: relative; 220 z-index: 2; 221 } 222 223 .partner-btn:hover { 224 transform: translateY(-2px); 225 box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); 226 text-decoration: none; 227 color: #5A6C7D; 228 border-color: rgba(74, 144, 226, 0.3); 229 background: rgba(255, 255, 255, 0.95); 230 } 231 232 .partner-logo { 233 width: 24px; 234 height: 24px; 235 object-fit: contain; 236 flex-shrink: 0; 237 } 238 239 .google-logo { 240 width: 24px; 241 height: 24px; 242 background: url('Photos/Images/HomePage/google.png') no-repeat center; 243 background-size: contain; 244 } 245 246 .microsoft-logo { 247 width: 24px; 248 height: 24px; 249 background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3QgeD0iMyIgeT0iMyIgd2lkdGg9IjguNSIgaGVpZ2h0PSI4LjUiIGZpbGw9IiNGMjUwMjIiLz4KPHJlY3QgeD0iMTIuNSIgeT0iMyIgd2lkdGg9IjguNSIgaGVpZ2h0PSI4LjUiIGZpbGw9IiM3RkJBMDAiLz4KPHJlY3QgeD0iMyIgeT0iMTIuNSIgd2lkdGg9IjguNSIgaGVpZ2h0PSI4LjUiIGZpbGw9IiMwMEE0RUYiLz4KPHJlY3QgeD0iMTIuNSIgeT0iMTIuNSIgd2lkdGg9IjguNSIgaGVpZ2h0PSI4LjUiIGZpbGw9IiNGRkI5MDAiLz4KPC9zdmc+Cg==') no-repeat center; 250 background-size: contain; 251 } 252 253 /* Specific fix for subtitle overlap at medium-large screens */ 254 @media (max-width: 1200px) and (min-width: 1144px) { 255 .hero-subtitle { 256 font-size: clamp(2rem, 3.2vw, 2.8rem); 257 white-space: nowrap; 258 } 259 } 260
261 /* Specific fix for medium screens where partner buttons overlap */ 262 @media (max-width: 1143px) and (min-width: 769px) { 263 .hero-component { 264 min-height: calc(100vh - 80px); 265 padding: 15px 0; 266 } 267 268 .hero-container { 269 padding: 0 30px; 270 min-height: 550px; 271 gap: 15px; 272 } 273 274 .hero-main { 275 grid-template-columns: 50% 50%; 276 gap: 0; 277 padding: 15px 0; 278 min-height: 400px; 279 } 280 281 .hero-content { 282 padding-right: 30px; 283 } 284 285 .hero-visual { 286 padding-left: 30px; 287 justify-content: center; 288 } 289 290 .hero-description { 291 font-size: clamp(0.95rem, 1.1vw, 1.1rem); 292 margin-bottom: 1.5rem; 293 max-width: 100%; 294 } 295 296 .hero-partners { 297 padding: 0 0 10px 0; 298 } 299 300 .partner-btn { 301 min-width: 200px; 302 height: 48px; 303 font-size: 0.85rem; 304 } 305 } 306 307 /* Mobile Responsive Design */ 308 @media (max-width: 1024px) { 309 .hero-component { 310 padding: 15px 0; 311 } 312 313 .hero-container { 314 padding: 0 30px; 315 min-height: 500px; 316 gap: 12px; 317 } 318 319 .hero-main { 320 grid-template-columns: 50% 50%; 321 gap: 0; 322 padding: 15px 0; 323 min-height: 380px; 324 } 325 326 .hero-content { 327 padding-right: 25px; 328 } 329 330 .hero-visual { 331 padding-left: 25px; 332 } 333 334 .hero-title { 335 font-size: clamp(2.25rem, 3.75vw, 3rem); 336 white-space: nowrap; 337 } 338 339 .hero-subtitle { 340 font-size: clamp(2rem, 3.5vw, 2.75rem); 341 white-space: nowrap; 342 } 343 344 .hero-description { 345 font-size: clamp(0.95rem, 1.1vw, 1.1rem); 346 margin-bottom: 1.8rem; 347 } 348 349 .partner-btn { 350 min-width: 200px; 351 height: 50px; 352 } 353 } 354 355 @media (max-width: 768px) { 356 .hero-component { 357 min-height: auto; 358 padding: 15px 0; 359 } 360 361 .hero-container { 362 padding: 0 20px; 363 min-height: auto; 364 gap: 15px; 365 } 366 367 .hero-main { 368 grid-template-columns: 1fr; 369 gap: 30px; 370 text-align: center; 371 padding: 10px 0; 372 min-height: auto; 373 } 374 375 .hero-content { 376 order: 2; 377 text-align: center; 378 align-items: center; 379 padding-right: 0; 380 } 381 382 .hero-visual { 383 order: 1; 384 justify-content: center; 385 padding-left: 0; 386 } 387 388 .hero-description { 389 max-width: 100%; 390 margin-bottom: 1.5rem; 391 } 392 393 .hero-image-container { 394 height: 300px; 395 } 396 397 .hero-partners { 398 padding: 0 0 10px 0; 399 flex-direction: column; 400 gap: 15px; 401 } 402 403 .partner-btn { 404 width: 100%; 405 max-width: 280px; 406 min-width: 280px; 407 justify-content: center; 408 height: 52px; 409 } 410 } 411 412 @media (max-width: 480px) { 413 .hero-container { 414 padding: 0 15px; 415 } 416 417 .hero-main { 418 gap: 30px; 419 } 420 421 .hero-title { 422 font-size: clamp(1.6rem, 5.2vw, 2rem); 423 margin-bottom: 0.8rem; 424 white-space: nowrap; 425 } 426 427 .hero-subtitle { 428 font-size: clamp(1.4rem, 5vw, 1.8rem); 429 margin-bottom: 1.2rem; 430 white-space: nowrap; 431 } 432 433 .hero-description { 434 font-size: clamp(0.95rem, 3.5vw, 1.1rem); 435 margin-bottom: 2rem; 436 } 437 438 .hero-cta-btn { 439 padding: 16px 32px; 440 font-size: 1rem; 441 } 442 443 .hero-image-container { 444 height: 280px; 445 } 446 447 .partner-btn { 448 padding: 12px 20px; 449 font-size: 0.85rem; 450 min-width: 260px; 451 max-width: 260px; 452 height: 48px; 453 } 454 } 455 456 /* Extra small screens */ 457 @media (max-width: 360px) { 458 .hero-title { 459 font-size: clamp(1.5rem, 6vw, 1.8rem); 460 white-space: nowrap; 461 } 462 463 .hero-subtitle { 464 font-size: clamp(1.3rem, 5.5vw, 1.6rem); 465 white-space: nowrap; 466 } 467 468 .hero-image-container { 469 height: 250px; 470 } 471 } 472 </style> 473 `; 474 } 475 476 // Generate the HTML structure for the hero component 477 generateHTML() { 478 const partnersHTML = this.config.showPartners ? ` 479 <div class="hero-partners"> 480 <a href="google-integration.html" class="partner-btn"> 481 <div class="google-logo"></div>
482 <span>Google for Education Partner</span> 483 </a> 484 <a href="microsoft-integration.html" class="partner-btn"> 485 <div class="microsoft-logo"></div> 486 <span>Microsoft Partner</span> 487 </a> 488 </div> 489 ` : ''; 490 491 return ` 492 <section class="hero-component"> 493 <div class="hero-container"> 494 <div class="hero-main"> 495 <div class="hero-content"> 496 <h1 class="hero-title">${this.config.title}</h1> 497 <h2 class="hero-subtitle">${this.config.subtitle}</h2> 498 <p class="hero-description">${this.config.description}</p> 499 <div class="hero-cta"> 500 <a href="${this.config.ctaUrl}" class="hero-cta-btn">${this.config.ctaText}</a> 501 </div> 502 </div> 503 504 <div class="hero-visual"> 505 <div class="hero-image-container"> 506 <img src="${this.config.heroImage}" alt="SchoolBlocks Platform Illustration" class="hero-image" /> 507 </div> 508 </div> 509 </div> 510 511 ${partnersHTML} 512 </div> 513 </section> 514 `; 515 } 516 517 // Render the complete hero component 518 render() { 519 return this.generateStyles() + this.generateHTML(); 520 } 521 522 // Initialize the hero component in a container 523 init(containerId) { 524 const container = document.getElementById(containerId); 525 if (container) { 526 container.innerHTML = this.render(); 527 } else { 528 console.error(`Hero Component: Container with id "${containerId}" not found`); 529 } 530 } 531 532 // Static method to create and render hero component 533 static create(config = {}, containerId = null) { 534 const hero = new HeroComponent(config); 535 if (containerId) { 536 hero.init(containerId); 537 } 538 return hero; 539 } 540} 541 542// Export for use in other files 543if (typeof module !== 'undefined' && module.exports) { 544 module.exports = HeroComponent; 545} 546 547// Make available globally 548window.HeroComponent = HeroComponent;
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.