|
218 | 218 |
|
219 | 219 |
|
220 | 220 |
|
221 | | - |
222 | 221 | <label class="md-header__button md-icon" for="__search"> |
223 | 222 |
|
224 | 223 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg> |
|
258 | 257 |
|
259 | 258 |
|
260 | 259 |
|
| 260 | + <div class="cs-products-menu"> |
| 261 | + <button type="button" class="cs-products-menu__trigger" aria-haspopup="true" aria-expanded="false"> |
| 262 | + Products |
| 263 | + <svg class="cs-products-menu__caret" viewBox="0 0 16 16" width="12" height="12" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6.5 8 10.5 12 6.5"/></svg> |
| 264 | + </button> |
| 265 | + <div class="cs-products-menu__popup" role="menu"> |
| 266 | + <div class="gs-rail"> |
| 267 | + <div class="gs-rail__group">Self-hosted</div> |
| 268 | + <a class="gs-opt gs-opt--feat gs-opt--on" role="menuitem" href="/" target="_blank" rel="noreferrer"> |
| 269 | + <span class="gs-opt__ic" aria-hidden="true"> |
| 270 | + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg> |
| 271 | + </span> |
| 272 | + <span class="gs-opt__body"> |
| 273 | + <span class="gs-opt__name">dstack</span> |
| 274 | + <span class="gs-opt__desc">The open-source control plane for AI-native orchestration.</span> |
| 275 | + </span> |
| 276 | + </a> |
| 277 | + <a class="gs-opt gs-opt--row external-skip" role="menuitem" href="https://calendly.com/dstackai/discovery-call" target="_blank" rel="noreferrer"> |
| 278 | + <span class="gs-opt__ic" aria-hidden="true"> |
| 279 | + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"/><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12"/><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17"/></svg> |
| 280 | + </span> |
| 281 | + <span class="gs-opt__body"> |
| 282 | + <span class="gs-opt__name">dstack Factory</span> |
| 283 | + <span class="gs-opt__desc">A complete software stack for AI labs, inference providers, and data centers.</span> |
| 284 | + </span> |
| 285 | + </a> |
| 286 | + <div class="gs-rail__group">Hosted by us</div> |
| 287 | + <a class="gs-opt gs-opt--row" role="menuitem" href="/products/sky" target="_blank" rel="noreferrer"> |
| 288 | + <span class="gs-opt__ic" aria-hidden="true"> |
| 289 | + <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/></svg> |
| 290 | + </span> |
| 291 | + <span class="gs-opt__body"> |
| 292 | + <span class="gs-opt__name">dstack Sky</span> |
| 293 | + <span class="gs-opt__desc">An AI cloud with AI-native orchestration. Rent GPUs on demand or bring your own compute.</span> |
| 294 | + </span> |
| 295 | + </a> |
| 296 | + </div> |
| 297 | + </div> |
| 298 | + </div> |
| 299 | + |
| 300 | + |
261 | 301 |
|
262 | 302 |
|
263 | 303 | <nav class="md-tabs" aria-label="Tabs" data-md-component="tabs"> |
|
380 | 420 | </svg> |
381 | 421 | </button> |
382 | 422 | <a href="https://github.com/dstackai/dstack" target="_blank" class="md-button md-button--primary github external-skip">GitHub</a> |
383 | | - |
384 | | - <div class="cs-gs-menu"> |
385 | | - <button type="button" class="md-button md-button--primary cs-gs-menu__trigger external-skip" aria-haspopup="true" aria-expanded="false"> |
386 | | - Get started |
387 | | - <svg class="cs-gs-menu__caret" viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 6.5 8 10.5 12 6.5"/></svg> |
388 | | - </button> |
389 | | - <div class="cs-gs-menu__popup" role="menu"> |
390 | | - |
391 | | - <div class="gs-rail"> |
392 | | - <div class="gs-rail__indicator" aria-hidden="true"></div> |
393 | | - <div class="gs-rail__group">Self-hosted</div> |
394 | | - <a class="gs-opt gs-opt--feat gs-opt--on" role="menuitem" href="/docs/installation/"> |
395 | | - <span class="gs-opt__icwrap"> |
396 | | - <span class="gs-opt__ic" aria-hidden="true"> |
397 | | - <svg viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.6 7.6 0 0 1 2-.27c.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg> |
398 | | - </span> |
399 | | - <span class="gs-opt__stars" data-cs-gh-stars hidden></span> |
400 | | - </span> |
401 | | - <span class="gs-opt__body"> |
402 | | - <span class="gs-opt__name">dstack</span> |
403 | | - <span class="gs-opt__desc">The open-source control plane for AI-native orchestration.</span> |
404 | | - </span> |
405 | | - </a> |
406 | | - <a class="gs-opt gs-opt--row external-skip" role="menuitem" href="https://calendly.com/dstackai/discovery-call" target="_blank" rel="noreferrer"> |
407 | | - <span class="gs-opt__ic" aria-hidden="true"> |
408 | | - <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg> |
409 | | - </span> |
410 | | - <span class="gs-opt__body"> |
411 | | - <span class="gs-opt__name">dstack Factory</span> |
412 | | - <span class="gs-opt__desc">Extends dstack with a governance and metering layer, and a private preset registry.</span> |
413 | | - </span> |
414 | | - </a> |
415 | | - <div class="gs-rail__group">Hosted by us</div> |
416 | | - <a class="gs-opt gs-opt--row external-skip" role="menuitem" href="https://sky.dstack.ai" target="_blank" rel="noreferrer"> |
417 | | - <span class="gs-opt__ic" aria-hidden="true"> |
418 | | - <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/></svg> |
419 | | - </span> |
420 | | - <span class="gs-opt__body"> |
421 | | - <span class="gs-opt__name">dstack Sky</span> |
422 | | - <span class="gs-opt__desc">Everything in dstack Factory, plus the GPU marketplace and the public preset registry.</span> |
423 | | - </span> |
424 | | - </a> |
425 | | - </div> |
426 | | - </div> |
427 | | - </div> |
428 | 423 | </div> |
429 | 424 | <script> |
430 | 425 | (function () { |
|
436 | 431 | } |
437 | 432 | }); |
438 | 433 |
|
439 | | - // "Get started" popup: click the trigger to toggle it; click anywhere outside (or the |
440 | | - // trigger again, or Escape) to close it. |
441 | | - var gsMenu = document.querySelector('.cs-gs-menu'); |
442 | | - var gsTrigger = gsMenu && gsMenu.querySelector('.cs-gs-menu__trigger'); |
443 | | - if (gsMenu && gsTrigger) { |
444 | | - var gsSetOpen = function (open) { |
445 | | - gsMenu.classList.toggle('cs-gs-menu--open', open); |
446 | | - gsTrigger.setAttribute('aria-expanded', open ? 'true' : 'false'); |
| 434 | + var productsMenu = document.querySelector('.cs-products-menu'); |
| 435 | + var productsTrigger = productsMenu && productsMenu.querySelector('.cs-products-menu__trigger'); |
| 436 | + if (productsTrigger) { |
| 437 | + var closeTimer; |
| 438 | + var productOptions = Array.from(productsMenu.querySelectorAll('.gs-opt')); |
| 439 | + var highlightProduct = function (selected) { |
| 440 | + productOptions.forEach(function (option) { |
| 441 | + option.classList.toggle('gs-opt--on', option === selected); |
| 442 | + }); |
| 443 | + }; |
| 444 | + var setProductsOpen = function (open) { |
| 445 | + clearTimeout(closeTimer); |
| 446 | + productsMenu.classList.toggle('cs-products-menu--open', open); |
| 447 | + productsTrigger.setAttribute('aria-expanded', String(open)); |
447 | 448 | }; |
448 | | - gsTrigger.addEventListener('click', function (e) { |
449 | | - e.stopPropagation(); |
450 | | - gsSetOpen(!gsMenu.classList.contains('cs-gs-menu--open')); |
| 449 | + productsMenu.addEventListener('mouseenter', function () { setProductsOpen(true); }); |
| 450 | + productsMenu.addEventListener('mouseleave', function () { |
| 451 | + highlightProduct(productOptions[0]); |
| 452 | + closeTimer = setTimeout(function () { |
| 453 | + if (!productsMenu.querySelector(':focus-visible')) setProductsOpen(false); |
| 454 | + }, 150); |
| 455 | + }); |
| 456 | + productsMenu.addEventListener('focusin', function () { setProductsOpen(true); }); |
| 457 | + productsMenu.addEventListener('focusout', function (e) { |
| 458 | + if (!productsMenu.contains(e.relatedTarget)) setProductsOpen(false); |
| 459 | + }); |
| 460 | + productsTrigger.addEventListener('click', function () { setProductsOpen(true); }); |
| 461 | + productOptions.forEach(function (option) { |
| 462 | + option.addEventListener('mouseenter', function () { highlightProduct(option); }); |
451 | 463 | }); |
452 | 464 | document.addEventListener('click', function (e) { |
453 | | - if (!gsMenu.contains(e.target)) gsSetOpen(false); |
| 465 | + if (!productsMenu.contains(e.target)) setProductsOpen(false); |
454 | 466 | }); |
455 | 467 | document.addEventListener('keydown', function (e) { |
456 | | - if (e.key === 'Escape') gsSetOpen(false); |
| 468 | + if (e.key === 'Escape') { |
| 469 | + if (productsMenu.contains(document.activeElement)) productsTrigger.focus(); |
| 470 | + setProductsOpen(false); |
| 471 | + } |
457 | 472 | }); |
458 | 473 | } |
459 | | - |
460 | | - // Sliding selection indicator (mirrors the landing rail): rests on the first row, moves |
461 | | - // to the hovered row. The popup is hidden via visibility (not display), so offsets are |
462 | | - // measurable even while closed. |
463 | | - var gsRail = gsMenu && gsMenu.querySelector('.gs-rail'); |
464 | | - if (gsRail) { |
465 | | - var gsInd = gsRail.querySelector('.gs-rail__indicator'); |
466 | | - var gsOpts = Array.prototype.slice.call(gsRail.querySelectorAll('.gs-opt')); |
467 | | - var gsPlace = function () { |
468 | | - var on = gsRail.querySelector('.gs-opt--on'); |
469 | | - if (!on) return; |
470 | | - // Fractional rect math (offsetTop/offsetHeight round to integers and leave 1px slivers). |
471 | | - var railBox = gsRail.getBoundingClientRect(); |
472 | | - var rowBox = on.getBoundingClientRect(); |
473 | | - var borderTop = parseFloat(getComputedStyle(gsRail).borderTopWidth) || 0; |
474 | | - gsInd.style.top = (rowBox.top - railBox.top - borderTop) + 'px'; |
475 | | - gsInd.style.height = rowBox.height + 'px'; |
476 | | - }; |
477 | | - gsOpts.forEach(function (opt) { |
478 | | - opt.addEventListener('mouseenter', function () { |
479 | | - gsOpts.forEach(function (o) { o.classList.remove('gs-opt--on'); }); |
480 | | - opt.classList.add('gs-opt--on'); |
481 | | - gsPlace(); |
482 | | - }); |
483 | | - }); |
484 | | - gsPlace(); |
485 | | - window.addEventListener('resize', gsPlace); |
486 | | - gsTrigger.addEventListener('click', gsPlace); |
487 | | - } |
488 | | - |
489 | | - // Live GitHub star count under the "Get started" popup's open-source icon (mirrors the |
490 | | - // landing). Best-effort: if the API is rate-limited or errors, the badge stays hidden. |
491 | | - var el = document.querySelector('[data-cs-gh-stars]'); |
492 | | - if (el) { |
493 | | - fetch('https://api.github.com/repos/dstackai/dstack') |
494 | | - .then(function (r) { return r.ok ? r.json() : null; }) |
495 | | - .then(function (d) { |
496 | | - if (!d || typeof d.stargazers_count !== 'number') return; |
497 | | - var n = d.stargazers_count, label; |
498 | | - if (n < 1000) label = String(n); |
499 | | - else { var k = n / 1000; label = (k >= 10 ? Math.round(k) : Number(k.toFixed(1))) + 'k'; } |
500 | | - el.textContent = label; |
501 | | - el.hidden = false; |
502 | | - if (typeof gsPlace === 'function') gsPlace(); |
503 | | - }) |
504 | | - .catch(function () {}); |
505 | | - } |
506 | 474 | })(); |
507 | 475 | </script> |
508 | 476 | </nav> |
|
0 commit comments