ampproject / amphtml

The AMP web component framework.
https://amp.dev
Apache License 2.0
14.89k stars 3.89k forks source link

FR: Navigation controller component #10395

Closed 10xjs closed 2 years ago

10xjs commented 7 years ago

As amp-bind becomes more powerful, it is becoming possible to create more app-like experiences in amp. A feature that would really augment this would be a method of navigating between different "views". This would unlock native style SAP experiences.

Currently this experience can be implemented with an amp-carousel that covers the entire viewport.

<style amp-custom>
  .view {
    height: 100%;
    overflow-y: scroll;
  }
  .amp-carousel-button {
    display: none;
  }
</style>

<amp-state id="viewIndex">
  <script type="application/json">0</script>
</amp-state>

<amp-carousel
  width="100vw"
  height="100vh"
  type="slides"
  [slide]="viewIndex"
  on="slideChange:AMP.setState({viewIndex: event.index})"
>
  <div>
    <div class="view>
      view 1 content
      <button on="tap:Amp.setState({viewIndex: 0})>Next</button>
    </div>
  </div>
  <div>
    <div class="view>
      view 2 content
      <button on="tap:Amp.setState({viewIndex: 1})>Back</button>
    </div>
  </div>
</amp-carousel>

This works but isn't ideal and feels like a complete misuse of the carousel component.

Since the body tag no longer scrolls vertically and instead carousel slide children provide vertical overflow, conflicts with other amp features are expected to arise.

Also, since the carousel is an enhanced horizontal scroll container, there is no way to prevent user from scrolling between views and views cannot be dynamically enabled or disabled.

An amp-navigation-controller could work as follows:

<amp-state id="view">
  <script type="application/json">"home"</script>
</amp-state>

<amp-state id="viewEnabled">
  <script type="application/json">false</script>
</amp-state>

<amp-navigation-controller id="navigation">
  <div view="home">
    <!-- go to `inner` or (`conditional` if not disabled) -->
    <button on="tap:navigation.next">Next</button>

    <!-- toggle conditional view -->
    <button on="tap:AMP.setState({viewEnabled: !viewEnabled})">Toggle Conditional</button>
  </div>

  <div view="conditional" disabled [disabled]="!viewEnabled">
    <!-- go to `inner` -->
    <button on="tap:navigation.next">Next</button>

    <!-- go to `last` -->
    <button on="tap:navigation.goTo('last')">Last</button>
  </div>

  <div view="inner">
  </div>

  <div view="last">
    <!-- go to `home` -->
    <button on="tap:navigation.goTo('home')">Home</button>

    <!-- go to `inner` -->
    <button on="tap:navigation.back">Home</button>
  </div>
</amp-navigation-controller>
aghassemi commented 7 years ago

/to @choumx @ericlindley-g

ericlindley-g commented 7 years ago

Thanks for filing this @10xjs !

This is really interesting, and really goes to the boundaries of what AMP is intended for. One pattern to achieve something similar is to combine AMP with PWA, but PWA support isn't universal.

I'd be curious to explore the tradeoffs here to see if it's something that's a good fit for AMP

/cc @cramforce for visibility

cramforce commented 7 years ago

I think doing long term evolution in this direction makes sense. I think we should study use cases first to see what the right interface would be.

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions.