motionsites中文站 / AI Assistant App
AI Assistant App
aadmin2026-09-22 发布App7 阅读

AI Assistant App

类型:App · 分类:AI App · 源码:会员可见

[hidecontent type="vip1"]
<!doctype html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <meta name="theme-color" content="#303238">

  <title>Nixito — Screen Gallery (Standalone)</title>

  <style>

    @font-face {

      font-family: "Mont Screen 3";

      src: url("assets/home/fonts/Mont-Screen3-Regular.woff2") format("woff2"),

           url("assets/home/fonts/Mont-Screen3-Regular.ttf") format("truetype");

      font-style: normal;

      font-weight: 400;

      font-display: swap;

    }

    @font-face {

      font-family: "Mont Screen 3";

      src: url("assets/home/fonts/Mont-Screen3-SemiBold.woff2") format("woff2"),

           url("assets/home/fonts/Mont-Screen3-SemiBold.ttf") format("truetype");

      font-style: normal;

      font-weight: 600;

      font-display: swap;

    }

    @font-face {

      font-family: "Mont Screen 3";

      src: url("assets/home/fonts/Mont-Screen3-Bold.woff2") format("woff2"),

           url("assets/home/fonts/Mont-Screen3-Bold.ttf") format("truetype");

      font-style: normal;

      font-weight: 700;

      font-display: swap;

    }



    :root {

      color-scheme: dark;

      --page: #08090d;

      --stage: #20232a;

      --stage-border: rgba(255, 255, 255, .13);

      --chrome: #242424;

      --muted: #a8a8a8;

      --screen-width: 390px;

      --screen-height: 844px;

      --rendered-screen-width: 390px;

      --rendered-screen-height: 844px;

      --screen-scale: 1;

      --stage-padding-y: clamp(20px, 4vh, 48px);

      font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

    }



    * { box-sizing: border-box; }



    html {

      min-width: 320px;

      min-height: 100%;

      background: #303238;

    }



    body {

      width: 100%;

      height: 100vh;

      height: 100dvh;

      margin: 0;

      overflow: hidden;

      background: #303238;

      color: #fff;

    }



    main {

      width: 100%;

      height: 100%;

    }



    .screen-gallery {

      width: 100%;

      height: 100vh;

      height: 100dvh;

      margin: 0;

      overflow-x: auto;

      overflow-y: hidden;

      border: 0;

      background: #303238;

      box-shadow:

        inset 0 1px 0 rgba(255, 255, 255, .07),

        inset 0 -1px 0 rgba(0, 0, 0, .24);

      scrollbar-color: #9299a5 #15181e;

      scrollbar-gutter: stable;

      scrollbar-width: auto;

      scroll-behavior: smooth;

      scroll-snap-type: x proximity;

      overscroll-behavior-inline: contain;

    }



    .screen-gallery.is-dragging {

      cursor: grabbing;

      scroll-behavior: auto;

      user-select: none;

    }



    .screen-gallery:focus-visible {

      outline: 2px solid #fff;

      outline-offset: 3px;

    }



    .screen-gallery::-webkit-scrollbar { height: 15px; }

    .screen-gallery::-webkit-scrollbar-track { background: #15181e; }

    .screen-gallery::-webkit-scrollbar-thumb {

      border: 4px solid #15181e;

      border-radius: 999px;

      background: #9299a5;

    }

    .screen-gallery::-webkit-scrollbar-thumb:hover { background: #c2c7cf; }



    .screen-track {

      display: flex;

      width: max-content;

      min-width: 100%;

      height: 100%;

      align-items: center;

      gap: clamp(32px, 2.5vw, 52px);

      padding: var(--stage-padding-y) clamp(42px, 3.25vw, 68px);

      cursor: grab;

    }



    .screen-card { cursor: auto; }



    .screen-card {

      position: relative;

      width: var(--rendered-screen-width);

      height: var(--rendered-screen-height);

      flex: 0 0 var(--rendered-screen-width);

      margin: 0;

      overflow: hidden;

      background: #fff;

      box-shadow:

        0 1px 0 rgba(255, 255, 255, .1),

        0 22px 54px rgba(0, 0, 0, .28);

      scroll-snap-align: center;

      scroll-snap-stop: normal;

    }



    screen-preview {

      display: block;

      width: var(--screen-width);

      height: var(--screen-height);

      background: #fff;

      transform: scale(var(--screen-scale));

      transform-origin: top left;

    }



    @media (max-width: 640px) {

      .screen-gallery {

        width: 100%;

        height: 100vh;

        height: 100dvh;

      }

      .screen-track { gap: 24px; padding-right: 20px; padding-left: 20px; }

    }



    @media (prefers-reduced-motion: reduce) {

      .screen-gallery { scroll-behavior: auto; }

    }

  </style>

</head>

<body>

  <main>

    <section id="screen-gallery" class="screen-gallery" aria-label="Nixito mobile screen gallery" tabindex="0">

      <div class="screen-track">



        <!-- SCREEN 1: Login -->

        <article class="screen-card" aria-label="Login screen">

          <screen-preview data-screen="login">

            <template>

              <style>

                @font-face {

                  font-family: "Mont";

                  src: url("assets/login/fonts/Mont-Regular.woff2") format("woff2");

                  font-weight: 400;

                  font-style: normal;

                  font-display: swap;

                }

                @font-face {

                  font-family: "Mont";

                  src: url("assets/login/fonts/Mont-SemiBold.woff2") format("woff2");

                  font-weight: 600;

                  font-style: normal;

                  font-display: swap;

                }



                :host { display: block; width: 390px; height: 844px; overflow: hidden; contain: strict; background: #fff; }

                .screen-body { width: 390px; height: 844px; min-width: 390px; min-height: 844px; overflow: hidden; }



                :host, :root {

                  --page: #ffffff;

                  --ink: #000000;

                  --muted: rgba(77, 77, 77, 0.6);

                  --border: #dfd5c9;

                  --pill-radius: 100px;

                  --card-radius: 16px;

                }

                * { box-sizing: border-box; }

                :host, .screen-body { min-width: 100%; min-height: 100%; margin: 0; }

                .screen-body {

                  display: grid;

                  place-items: start center;

                  overflow-x: auto;

                  background: #ececec;

                  color: var(--ink);

                  font-family: "Mont", Arial, sans-serif;

                }

                button, input { font: inherit; }

                .app-screen {

                  position: relative;

                  width: 390px;

                  height: 844px;

                  flex: 0 0 390px;

                  overflow: hidden;

                  background: var(--page) url("assets/login/images/login-background.png") center / cover no-repeat;

                }

                .login-panel {

                  position: absolute;

                  top: 100px;

                  left: 40px;

                  z-index: 2;

                  display: flex;

                  width: 310px;

                  height: 400px;

                  flex-direction: column;

                  align-items: center;

                  gap: 30px;

                }

                h1 {

                  width: 275px;

                  height: 72px;

                  margin: 0;

                  font-size: 32px;

                  font-weight: 600;

                  line-height: 36px;

                  text-align: center;

                }

                .form-fields {

                  display: flex;

                  width: 310px;

                  height: 210px;

                  flex-direction: column;

                  gap: 16px;

                }

                .field-group {

                  display: flex;

                  width: 310px;

                  flex-direction: column;

                  align-items: flex-start;

                  gap: 4px;

                }

                .field-group label {

                  height: 20px;

                  padding-left: 12px;

                  color: var(--muted);

                  font-size: 14px;

                  font-weight: 400;

                  line-height: 20px;

                }

                .field-shell {

                  display: flex;

                  width: 310px;

                  height: 54px;

                  align-items: center;

                  padding: 16px 28px 16px 24px;

                  border: 1px solid var(--border);

                  border-radius: 30px;

                }

                .field-shell input {

                  width: 100%;

                  margin: 0;

                  padding: 0;

                  border: 0;

                  outline: 0;

                  background: transparent;

                  color: var(--ink);

                  font-size: 16px;

                  font-weight: 400;

                  line-height: 22px;

                  pointer-events: none;

                }

                .password-section {

                  display: flex;

                  width: 310px;

                  height: 116px;

                  flex-direction: column;

                  align-items: flex-end;

                  gap: 16px;

                }

                .password-group { height: 80px; }

                .password-shell { height: 56px; justify-content: space-between; }

                .password-shell input { width: 175px; padding-top: 5px; font-weight: 400; letter-spacing: 0; }

                .visibility-icon { flex: 0 0 auto; color: var(--ink); }

                .forgot-password {

                  width: 127px;

                  height: 20px;

                  margin: 0;

                  color: var(--muted);

                  font-size: 14px;

                  font-weight: 400;

                  line-height: 20px;

                  white-space: nowrap;

                }

                .login-button {

                  display: flex;

                  width: 310px;

                  height: 58px;

                  align-items: center;

                  justify-content: center;

                  padding: 17px 0;

                  border: 0;

                  border-radius: var(--pill-radius);

                  background: var(--ink);

                  color: #ffffff;

                  font-size: 20px;

                  font-weight: 600;

                  line-height: 24px;

                }

                .robot-gallery {

                  position: absolute;

                  inset: 0;

                  z-index: 1;

                  pointer-events: none;

                }

                .robot-card {

                  position: absolute;

                  width: 80px;

                  height: 110px;

                  overflow: hidden;

                  border-radius: var(--card-radius);

                  background: #d9d9d9;

                  transform-origin: center;

                }

                .robot-card img {

                  position: absolute;

                  display: block;

                  max-width: none;

                  object-fit: fill;

                  transform-origin: 0 0;

                }

                .card-ant { top: 534.89px; left: -44.94px; transform: rotate(10deg); }

                .card-ant img { top: -10.1573px; left: -21.1976px; width: 153.3427px; height: 114.802px; transform: rotate(5deg); }

                .card-orange { top: 567.72px; left: 55.36px; transform: rotate(5deg); }

                .card-orange img { inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 29%; transform: none; }

                .card-tractor { top: 601px; left: 156px; }

                .card-tractor img { inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 51% center; transform: none; }

                .card-runner { top: 567.72px; left: 247.36px; transform: rotate(-5deg); }

                .card-runner img { top: -36px; left: -67px; width: 269px; height: 201px; }

                .card-koala { top: 534.89px; left: 339.06px; transform: rotate(-10deg); }

                .card-koala img { inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% center; transform: none; }

                .signup-copy {

                  position: absolute;

                  top: 784px;

                  left: 118px;

                  z-index: 2;

                  width: 155px;

                  height: 20px;

                  margin: 0;

                  color: #4d4d4d;

                  font-size: 14px;

                  font-weight: 400;

                  line-height: 20px;

                  white-space: nowrap;

                }

                .signup-copy span {

                  color: var(--ink);

                  text-decoration: underline;

                  text-decoration-thickness: 1px;

                  text-underline-offset: 2px;

                }

              </style>

              <div class="screen-body">

                <main class="app-screen" aria-label="Rovio login screen">

                  <section class="login-panel">

                    <h1>Welcome Back<br>to Rovio</h1>

                    <div class="form-fields">

                      <div class="field-group">

                        <label for="email">E-mail</label>

                        <div class="field-shell">

                          <input id="email" type="text" value="hello.nixtio@gmail.com" readonly tabindex="-1">

                        </div>

                      </div>

                      <div class="password-section">

                        <div class="field-group password-group">

                          <label for="password">Password</label>

                          <div class="field-shell password-shell">

                            <input id="password" type="text" value="************" readonly tabindex="-1">

                            <svg class="visibility-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" aria-hidden="true">

                              <path d="M19.439 15.439C20.3636 14.5212 21.0775 13.6091 21.544 12.955C21.848 12.5287 22 12.3155 22 12C22 11.6845 21.848 11.4713 21.544 11.045C20.1779 9.12944 16.6892 5 12 5C11.0922 5 10.2294 5.15476 9.41827 5.41827M6.74742 6.74742C4.73118 8.1072 3.24215 9.94266 2.45604 11.045C2.15201 11.4713 2 11.6845 2 12C2 12.3155 2.15201 12.5287 2.45604 12.955C3.8221 14.8706 7.31078 19 12 19C13.9908 19 15.7651 18.2557 17.2526 17.2526" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>

                              <path d="M9.85786 10C9.32783 10.53 9 11.2623 9 12.0711C9 13.6887 10.3113 15 11.9289 15C12.7377 15 13.47 14.6722 14 14.1421" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>

                              <path d="M3 3L21 21" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>

                            </svg>

                          </div>

                        </div>

                        <p class="forgot-password">Forgot password?</p>

                      </div>

                    </div>

                    <button class="login-button" type="button">Log in</button>

                  </section>

                  <section class="robot-gallery" aria-label="Robot artwork">

                    <div class="robot-card card-ant"><img src="https://flick-award-65707097.figma.site/_assets/v11/3d4592287a68a77e1f39468956467f77b99e0be9.png?w=1024" alt="White ant robot"></div>

                    <div class="robot-card card-orange"><img src="https://flick-award-65707097.figma.site/_assets/v11/d74df0660205f97a394bf111698bfbc3bf9a6d02.png?h=1536" alt="White and orange robot"></div>

                    <div class="robot-card card-tractor"><img src="https://flick-award-65707097.figma.site/_assets/v11/692faeeb8862706819c2a2488880f6f2766f051f.png?w=1024" alt="Red robot tractor"></div>

                    <div class="robot-card card-runner"><img src="https://flick-award-65707097.figma.site/_assets/v11/a042994ae16f2819fe2e45d88c2afafd1fa9c526.png?w=1024" alt="Running white robot"></div>

                    <div class="robot-card card-koala"><img src="https://flick-award-65707097.figma.site/_assets/v11/998fc400e7936fff51f0830a447fd86bdead2ced.png?w=1024" alt="White koala robot"></div>

                  </section>

                  <p class="signup-copy">New to Rovio? <span>Sign up</span></p>

                </main>

              </div>

            </template>

          </screen-preview>

        </article>



        <!-- SCREEN 2: Start / Onboarding -->

        <article class="screen-card" aria-label="Start screen">

          <screen-preview data-screen="start">

            <template>

              <style>

                @font-face {

                  font-family: "Mont";

                  src: url("assets/start/fonts/Mont-Regular.woff2") format("woff2");

                  font-style: normal;

                  font-weight: 400;

                  font-display: swap;

                }

                @font-face {

                  font-family: "Mont";

                  src: url("assets/login/fonts/Mont-SemiBold.woff2") format("woff2");

                  font-style: normal;

                  font-weight: 600;

                  font-display: swap;

                }

                @font-face {

                  font-family: "Mont";

                  src: url("assets/start/fonts/Mont-Bold.woff2") format("woff2");

                  font-style: normal;

                  font-weight: 700;

                  font-display: swap;

                }



                :host { display: block; width: 390px; height: 844px; overflow: hidden; contain: strict; background: #fff; }

                .screen-body { width: 390px; height: 844px; min-width: 390px; min-height: 844px; overflow: hidden; }



                :host, :root {

                  color: #050505;

                  font-family: Mont, "Arial Rounded MT Bold", Arial, sans-serif;

                }

                * { box-sizing: border-box; }

                .screen-body { min-width: 390px; min-height: 100vh; margin: 0; background: #151515; }

                .onboarding {

                  position: relative;

                  isolation: isolate;

                  width: 390px;

                  height: 844px;

                  margin: auto;

                  overflow: visible;

                  background: #babfba;

                }

                .robot {

                  position: absolute;

                  z-index: 1;

                  top: 298px;

                  left: 0;

                  width: 390px;

                  height: 546px;

                  object-fit: fill;

                  display: block;

                }

                .progress {

                  display: flex;

                  position: absolute;

                  z-index: 2;

                  top: 50px;

                  left: 35px;

                  gap: 6px;

                  align-items: center;

                  height: 4px;

                  width: 321px;

                }

                .progress span {

                  display: block;

                  width: 103px;

                  height: 4px;

                  border-radius: 20px;

                  background: rgba(0, 0, 0, .2);

                }

                .progress .is-active { background: #050505; }

                .app-icon {

                  position: absolute;

                  z-index: 3;

                  top: 313px;

                  left: 332px;

                  width: 120px;

                  height: 120px;

                  object-fit: contain;

                  transform: none;

                }

                h1 {

                  position: absolute;

                  z-index: 2;

                  top: 111px;

                  left: 40px;

                  width: 310px;

                  margin: 0;

                  font-family: "Mont", Arial, sans-serif;

                  font-size: 48px;

                  font-weight: 600;

                  letter-spacing: 0;

                  line-height: 52px;

                }

                .cta {

                  position: absolute;

                  z-index: 2;

                  right: 40px;

                  bottom: 40px;

                  left: 40px;

                  height: 58px;

                  border: 0;

                  border-radius: 999px;

                  color: white;

                  background: #000;

                  font: 500 20px/24px Mont, "Arial Rounded MT Bold", Arial, sans-serif;

                  cursor: pointer;

                  transition: transform .18s ease, background .18s ease;

                }

                .cta:hover { background: #191919; }

                .cta:active { transform: scale(.97); }

                .cta:focus-visible { outline: 2px solid white; outline-offset: -5px; }

              </style>

              <div class="screen-body">

                <main class="onboarding" aria-labelledby="headline">

                  <img class="robot" src="https://flick-award-65707097.figma.site/_assets/v11/4f94f64504ce0aa87a72ede57dace8a3f878c98a.png" alt="" />

                  <nav class="progress" aria-label="Onboarding progress">

                    <span></span><span></span><span class="is-active"></span>

                  </nav>

                  <img class="app-icon" src="https://flick-award-65707097.figma.site/_assets/v11/c282fcce51bbc257dddef6e7bd172667eab47b07.png" alt="" />

                  <h1 id="headline">Speak the World's<br />Language!</h1>

                  <button class="cta" type="button">Get started</button>

                </main>

              </div>

            </template>

          </screen-preview>

        </article>



      </div>

    </section>

  </main>



  <script>

    class ScreenPreview extends HTMLElement {

      connectedCallback() {

        if (this.shadowRoot) return;

        const template = this.querySelector(':scope > template');

        if (!template) return;

        const shadow = this.attachShadow({ mode: 'open' });

        shadow.append(template.content.cloneNode(true));

        template.remove();



        if (this.dataset.screen === 'start') {

          const button = shadow.querySelector('.cta');

          button?.addEventListener('click', () => {

            button.textContent = "Letu2019s go!";

            button.setAttribute('aria-label', 'Getting started');

          });

        }

      }

    }

    customElements.define('screen-preview', ScreenPreview);



    const gallery = document.querySelector('#screen-gallery');

    const cards = [...document.querySelectorAll('.screen-card')];



    let activeIndex = 0;

    let frameRequest = 0;

    let dragStartX = 0;

    let dragStartScroll = 0;

    let isDragging = false;



    function fitScreensToViewport() {

      const track = gallery.querySelector('.screen-track');

      const trackStyles = getComputedStyle(track);

      const paddingTop = Number.parseFloat(trackStyles.paddingTop) || 0;

      const paddingBottom = Number.parseFloat(trackStyles.paddingBottom) || 0;

      const paddingLeft = Number.parseFloat(trackStyles.paddingLeft) || 0;

      const paddingRight = Number.parseFloat(trackStyles.paddingRight) || 0;

      const availableHeight = Math.max(1, gallery.clientHeight - paddingTop - paddingBottom);

      const availableWidth = Math.max(1, gallery.clientWidth - paddingLeft - paddingRight);

      const scale = Math.min(1, availableHeight / 844, availableWidth / 390);



      document.documentElement.style.setProperty('--screen-scale', scale.toFixed(5));

      document.documentElement.style.setProperty('--rendered-screen-width', `${390 * scale}px`);

      document.documentElement.style.setProperty('--rendered-screen-height', `${844 * scale}px`);

    }



    function nearestCardIndex() {

      const galleryCenter = gallery.scrollLeft + gallery.clientWidth / 2;

      let nearestIndex = 0;

      let nearestDistance = Number.POSITIVE_INFINITY;

      cards.forEach((card, index) => {

        const cardCenter = card.offsetLeft + card.offsetWidth / 2;

        const distance = Math.abs(cardCenter - galleryCenter);

        if (distance < nearestDistance) {

          nearestDistance = distance;

          nearestIndex = index;

        }

      });

      return nearestIndex;

    }



    function updateActiveIndex() { activeIndex = nearestCardIndex(); }



    function scrollToCard(index) {

      const boundedIndex = Math.max(0, Math.min(cards.length - 1, index));

      cards[boundedIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });

    }



    gallery.addEventListener('keydown', (event) => {

      if (event.key === 'ArrowLeft') { event.preventDefault(); scrollToCard(activeIndex - 1); }

      else if (event.key === 'ArrowRight') { event.preventDefault(); scrollToCard(activeIndex + 1); }

      else if (event.key === 'Home') { event.preventDefault(); scrollToCard(0); }

      else if (event.key === 'End') { event.preventDefault(); scrollToCard(cards.length - 1); }

    });



    gallery.addEventListener('scroll', () => {

      cancelAnimationFrame(frameRequest);

      frameRequest = requestAnimationFrame(updateActiveIndex);

    }, { passive: true });



    gallery.addEventListener('wheel', (event) => {

      if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) return;

      const atStart = gallery.scrollLeft <= 0;

      const atEnd = gallery.scrollLeft >= gallery.scrollWidth - gallery.clientWidth - 1;

      if ((event.deltaY < 0 && atStart) || (event.deltaY > 0 && atEnd)) return;

      event.preventDefault();

      gallery.scrollLeft += event.deltaY;

    }, { passive: false });



    gallery.addEventListener('pointerdown', (event) => {

      if (event.button !== 0 || event.target.closest('.screen-card')) return;

      isDragging = true;

      dragStartX = event.clientX;

      dragStartScroll = gallery.scrollLeft;

      gallery.classList.add('is-dragging');

      gallery.setPointerCapture(event.pointerId);

    });



    gallery.addEventListener('pointermove', (event) => {

      if (!isDragging) return;

      gallery.scrollLeft = dragStartScroll - (event.clientX - dragStartX);

    });



    function stopDragging(event) {

      if (!isDragging) return;

      isDragging = false;

      gallery.classList.remove('is-dragging');

      if (gallery.hasPointerCapture(event.pointerId)) gallery.releasePointerCapture(event.pointerId);

    }



    gallery.addEventListener('pointerup', stopDragging);

    gallery.addEventListener('pointercancel', stopDragging);



    window.addEventListener('resize', () => {

      fitScreensToViewport();

      updateActiveIndex();

    }, { passive: true });



    fitScreensToViewport();

    updateActiveIndex();

  </script>

</body>

</html>
[/hidecontent]
← 返回首页