Amphtml: Create amp-date-countdown component

Created on 12 Jul 2017  Ā·  31Comments  Ā·  Source: ampproject/amphtml

Requirements

MVP

  • Ability to set an enddate (probably ISO format with optional timezone section similar to amp-timeago) and get some default out of the box rendering. (e.g. 2 days 10 hours 2 minutes 30 seconds )
  • Ability to customize and internationalize the format: (e.g. 3 jours 10:02:30)

    • Since numbers are dynamic, pluralization of the words matter here

  • Ability to provide formats where groupings are different. For instance instead of 1 month 20 days publisher may prefer 50 days
  • Ability to use CSS to style each part (number and text) so publisher could do renderings such as:
    a
  • Ability to write CSS that would allow animation when numbers change (this probably means we either need to reset the class or remove/reinsert instead of just changing innerText)
  • Ability to specify what happens when it reaches the end. Maybe publisher wants it to stay at 0 or they may it to keep going in the opposite direction.

Non-MVP

Maybe a separate component makes sense for this, anyway not something to worry about initially.

  • Ability to turn this into a timer instead of a countdown by providing number of second instead of an end date. (e.g. 200 -> 199 -> ... -> 0 or 0 -> 1 -> 2 ... -> <some end number>)
  • Ability to manually play and pause the timer.
  • Ability for the timer to only start when it comes to view.

Format Design

See presentation for a summary.

<amp-date-countdown 
  datetime=ā€ISO with optional time/timezone offsetā€
  timestamp-ms="POSIX epoch in ms"
  timestamp-seconds="POSIX epoch in seconds" 
  offset-seconds=ā€secondsā€
  locale=ā€en-US|navigatorā€
  when-ended="stop|continue"
  layout="OnlySizedDefinedLayouts">
 <template type="amp-mustache">
    {{#days}}<span>{{day}} {{dayWord}}</span>{{/days}}
    <span>{{hour}} {{hourWord}}</span>
    <span>{{minute}} {{minuteWord}}</span>
    <span>{{secondTwoDigit}} {{seondWord}}</span>
 </template>
</amp-date-countdown>

possible outputs:

68 days 0 hours 1 minute 20 seconds
0 hours 1 minute 20 seconds
0 hours 0 minutes 01 second

Template Variables

This proposal handles "don't want to show 0" easily using mustache sections (e.g. {{#day}}) and does not need anything for grouping which are big advantages.

Variables | Meaning
--- | ---
year | year - 0..Infinity
month | month - 0, 1, 2, 3...Infinity
monthTwoDigits | month - 00, 01, 02, 03...Infinity
| ....
yearWord| i18n string for year or years
monthWord | i18n string for month or month
| ....

Attributes

datetime

  • One of now or <ISO datetime> with OPTIONAL time and timezone offset
  • If no time/timezone specified, assumes local otherwise utc

timestamp-ms

  • POSIX epoch value in milliseconds - will be assumed to be UTC

timestamp-seconds

  • POSIX epoch value in seconds - will be assumed to be UTC

Note: _One_ of datetime, timestamp-ms, timestamp-seconds is required.

offset-seconds

  • Negative or poissive number of seconds to add/subtract from datetime

when-ended

  • One of stop continue

Auto merge of remaining time

  • We need to support both 1 month 20 days == 50 days
  • Component finds the "highest" part used and automatically folds the remaining time there

Example: assume there is 50 days, 10 hours left:
<span>{{month}} {{monthWord}} {{days}} {{dayWord}} {{hour}} {{hourWord}}</span> -> 1 month 21 days 10 hours
<span>{{day}} {{dayWord}} {{hour}} {{hourWord}} -> 50 days 10 hours
{{hour}} {{hourWord}} -> 1210 hours

When Possible Feature Request

Most helpful comment

@ethereal-sandeep sorry for the delay, sounds good to me! thanks for volunteering, very much appreciated.

For requirements, here is what I have in mind:

MVP

  • [ ] Ability to set an enddate (probably ISO format with optional timezone section similar to amp-timeago) and get some default out of the box rendering. (e.g. 2 days 10 hours 2 minutes 30 seconds )
  • [ ] Ability to customize and internationalize the format: (e.g. 3 jours 10:02:30)

    • [ ] Since numbers are dynamic, pluralization of the words matter here

  • [ ] Ability to provide formats where groupings are different. For instance instead of 1 month 20 days publisher may prefer 50 days
  • [ ] Ability to use CSS to style each part (number and text) so publisher could do renderings such as:
    a
  • [ ] Ability to write CSS that would allow animation when numbers change (this probably means we either need to reset the class or remove/reinsert instead of just changing innerText)
  • [ ] Ability to specify what happens when it reaches the end. Maybe publisher wants it to stay at 0 or they may it to keep going in the opposite direction.

Non-MVP

Maybe a separate component makes sense for this, anyway not something to worry about initially.

  • [ ] Ability to turn this into a timer instead of a countdown by providing number of second instead of an end date. (e.g. 200 -> 199 -> ... -> 0 or 0 -> 1 -> 2 ... -> <some end number>)
  • [ ] Ability to manually play and pause the timer.
  • [ ] Ability for the timer to only start when it comes to view.

/cc @ericlindley-g for other thoughts.

@ethereal-sandeep, I have some ideas for a design, best approach might be you also come up with a design and then we can have a session to discuss and come up with a final version to document and present in one of AMP's design review meetings (they are open to public if you like to attend). What do you think?

All 31 comments

Worth looking at time-ago and whether it can handle both? Negative times?

Hi @aghassemi i would like to work on this if its not claimed yet !!

@ethereal-sandeep Great! before you commit, just disclaimer that this is not quite a GFI yet (hence the GFI Candidate label) as it requires API design first and is a bigger commitment than normal GFIs. If you are interested in both designing and implementing it, let me know. If not, I recommend picking one of the existing smaller GFIs.

If you decide to take it, please ping me here so we can start collaboration on the API requirements.

Thanks!

Yes I would love to take it up and work on both designing and implementing.

Thanks !

Lets start with API requirements.

@ethereal-sandeep sorry for the delay, sounds good to me! thanks for volunteering, very much appreciated.

For requirements, here is what I have in mind:

MVP

  • [ ] Ability to set an enddate (probably ISO format with optional timezone section similar to amp-timeago) and get some default out of the box rendering. (e.g. 2 days 10 hours 2 minutes 30 seconds )
  • [ ] Ability to customize and internationalize the format: (e.g. 3 jours 10:02:30)

    • [ ] Since numbers are dynamic, pluralization of the words matter here

  • [ ] Ability to provide formats where groupings are different. For instance instead of 1 month 20 days publisher may prefer 50 days
  • [ ] Ability to use CSS to style each part (number and text) so publisher could do renderings such as:
    a
  • [ ] Ability to write CSS that would allow animation when numbers change (this probably means we either need to reset the class or remove/reinsert instead of just changing innerText)
  • [ ] Ability to specify what happens when it reaches the end. Maybe publisher wants it to stay at 0 or they may it to keep going in the opposite direction.

Non-MVP

Maybe a separate component makes sense for this, anyway not something to worry about initially.

  • [ ] Ability to turn this into a timer instead of a countdown by providing number of second instead of an end date. (e.g. 200 -> 199 -> ... -> 0 or 0 -> 1 -> 2 ... -> <some end number>)
  • [ ] Ability to manually play and pause the timer.
  • [ ] Ability for the timer to only start when it comes to view.

/cc @ericlindley-g for other thoughts.

@ethereal-sandeep, I have some ideas for a design, best approach might be you also come up with a design and then we can have a session to discuss and come up with a final version to document and present in one of AMP's design review meetings (they are open to public if you like to attend). What do you think?

MVP and NON-MVP both requirements sounds Awesome. For design i have few thoughts so lets have a session and from there onward's I will start with MVP and then move on to NON-MVP. It would be great to be part of AMP's design review meetings. Thanks!

At first glance looks great!

A couple things occur to me:

  1. Agree that it makes sense to split into MVP and future improvements, and wonder if there's even more paring down we can do for the MVP. Here are some examples that might help scope it:

ex.
https://countingdownto.com/
https://www.timeanddate.com/countdown/create
http://itsalmo.st/#
https://www.tickcounter.com/
http://www.xmasclock.com/

Possible things to do after MVP:

  • option to keep counting after reaching the bottom (I suspect we can just choose "stopping at end" for MVP)
  • how many formats to support (I suspect we could launch with a single format that just splits everything into year month day hour minute second, but would be curious if the other routes are trivially easy to implement)
  1. Additional feature after MVP: when creating different groupings (i.e. 50 days instead of 1 month 20 days), we may also want to think about what to display when you just show higher-order groupings (e.g. when you just want to show days, rather than all the hours/minutes/seconds as well). For instance, "34 days, 23 hours, 5 minutes, 2 seconds" would probably be rounded up and shown as "35 days".

Then what happens when there's less than 1 day left? I imagine the most common use case would be to go into hours (rounded up) at that point (e.g. show "23 hours" instead of "1 day" or "22 hours, 59 minutes, 59 seconds" or "0 days, 22 hours, .... "), then when there's less than 1 hour left, show minutes (e.g. "59 minutes" rather than "1 hour", etc.)

  1. Additional feature after MVP: might want the ability to bind to the completion state (and maybe states in between), so that more than just the layout of the timer itself can change when it completes /cc @choumx for visibility

  2. I'll be curious to hear how we're approaching internationalizing and pluralizing items in the format. I'm guessing the component wouldn't take on the complexity here, but provide just enough hooks for users to do it, and provide examples. (?)

Either way, excited to get this feature added to the format! Would be great to do a design review with in the weekly meeting when there's a design written up

Some e-commerce use cases for the MVP or beyond:

5p3xgthtfkc

ow3xurp9wwo

For both eBay and Amazon, the least significant units (minute, second) only activate when the more significant units (day, hour) equal zero.

I assume something also happens when zero is reached.

Will this be implemented via <amp-bind>?

<p [text]="[hour, 'h ', minute, 'm ', second, 's'].join('')"></p>

Good call @ithinkihaveacat — thanks for adding this use case

We'll want to be careful about what can be triggered when zero is reached, given that we don't want to support bad UX (e.g. Ad interstitials that count down, ads that pop up after a certain amount of time). Maybe there's a way to scope the kinds of actions that can be triggered by a reached-zero event? ( /cc @choumx — this relates to the user action trust-levels we've been talking about) Or maybe we narrowly scope a few things that can happen based on the event, but don't expose the event broadly?

Great discussions here. To get the ball rolling, let's start the design collaboration and maybe present the format for MVP feature on August 2nd's AMP Design Review Meeting

@ethereal-sandeep Here are my ideas for the format, please add your thoughts as well.

API Proposal 1

<amp-countdown 

  end-date="ISO Date"
  format="See format section"
  when-ended="stop|continue"
  layout="OnlySizedDefinedLayouts">

No Children Allowed
</amp-countdown>

end-date

An ISO formatted date to count down to. e.g. 2017-11-11T00:37:33.809Z

when-ended

One of stop or continue. Stop would leave everything at 0. Continue would start counting in the opposite direction.

format

Let's start with a few examples first:

Format | Sample Output
--- | ---
{hh}:{mm}:{ss} | 04:24:06
{h} {hours} and {m} {minutes} and {s} {seconds} | 4 hours and 1 minute and 45 seconds
{d} {days} {h}:{mm} | 1 day 5:03
{d} {days} {h} {hour} {m} {minute} | 50 days 5 hours 10 minutes
{M} {months} {d} {days} {h} {hours} {m} {minutes} | 1 month 20 days 5 hours 10 minutes
{Y} {years} {M} {months} {d} {days} {h} {hours} {m} {minutes} | 0 years 1 month 20 days 5 hours 10 minutes

Details

Format | Meaning
--- | ---
Y | year - 10..Infinity
M | month - 0, 1, 2, 3..Infinity
MM | month - 00, 01, 02, 03..Infinity
d | day - 0, 1, 2,...12, 13..Infinity
dd | day - 00, 01, 02, 03..Infinity
h | hour - 0, 1, 2,...12, 13..Infinity
hh | hour - 01, 02, 03..Infinity
m | minute - 0, 1, 2,...12, 13..Infinity
mm | minute - 01, 01, 02, 03..Infinity
s | second - 0, 1, 2,...12, 13..Infinity
ss | second - 00, 01, 02, 03..Infinity
years | i18n string for year or years
months | i18n string for month or month
days | i18n string for day or days
hours | i18n string for hour or hours
minutes | i18n string for minute or minutes
seconds | i18n string for second or seconds

Output

Every part is rendered into its own <span> with a part=<year, year-text, ..., second, second-text, literal> attribute on the span.

Literals are parts of the format that are not replaced (e.g. : and, whitespace).

Parenthesis can be used create additional <span> groupings which get a part="group" attribute.
Examples:

Format | Sample Output
--- | ---
{hh}:{mm} to dawn | <span part="hour">11</span><span part="literal">:</span><span part="minute">10</span><span part="literal"> to dawn</span>
({d}{days})({h}{hours}) | <span part="group"><span part="day">11</span><span part="day-text">days</span></span><span part="group"><span part="hour">1</span><span part="hour-text">hour</span></span>

This would allow very flexible styling through CSS.

Also note that the component finds the "highest" part used and automatically fills the remaining time there.

For instance assume there is 50 days, 10 hours left:
{M} {months} {d} {days} {H} {hours} -> 1 month 21 days 10 hours
{d} {days} {H} {hours} -> 50 days 10 hours
{H} {hours} -> 1210 hours

API Proposal 2

This proposal is based on @andreban's comment below and suggests using amp-mustache instead of custom format strings.

<amp-countdown 
  end-date="ISO Date"
  when-ended="stop|continue"
  layout="OnlySizedDefinedLayouts">

 <template type="amp-mustache">
     {{#days}}<div>{{days}} {{dayStr}}</div>{{#daysl}}
    <span>{{hours}} {hourStr}</span>
    <span>{{minutes}} {minuteStr}</span>
    <span>{{secondsTwoDigit}} {seondStr}</span>
 </template>

</amp-countdown>

possible outputs:

68 days 0 hours 1 minute 20 seconds
0 hours 1 minute 20 seconds
0 hours 0 minutes 01 second

Template Variables

Essentially we will provide all the exposed variables in format from above as variables.

This proposal handles "don't want to show 0" easily using mustache sections (e.g. {{#day}}) and does not need anything for grouping which are big advantages.

Similar to proposal 1, the component finds the "highest" part used and automatically fills the remaining time there.

Variables | Meaning
--- | ---
years | year - 0..Infinity
months | month - 0, 1, 2, 3...Infinity
monthsTwoDigits | month - 00, 01, 02, 03...Infinity
| ....
yearStr | i18n string for year or years
monthStr | i18n string for month or month
| ....

Examples

Questions for Proposal 1:
1- Should we add an ended attribute to the component when it ends to it can be targeted with CSS? (has potential abuse through adjacent selectors)
2- How about when a part reaches '0'? (so they can targeted with CSS. e.g. change color to red, hide, etc..). Less abuse potential here.
3- How to handle CSS transitions? We could define an attribute e.g. updated that we add and remove every time a part is updated so CSS transitions rerun? (e.g. amp-countdown [updated] { transition: opacity: 1; transition: opacity .25s ease-in-out; })

Questions for Proposal 2:
1- If we can't detect what variables are used in the template, we may need to expose monthTotal monthStr and monthStrTotal etc...
2- If 0 is not considered falsy in Mustache, we would need to expose isDayNonZero , etc...

@aghassemi sorry for the delay in replying. The API draft looks awesome.

  1. I thinks adding ended would be nice as it would allow for end state to have a different look and feel from the running state.
<amp-countdown 
  ended="true/false'
  end-date="ISO Date"
  format="See format section"
  when-ended="stop|continue"
  layout="OnlySizedDefinedLayouts">

No Children Allowed
</amp-countdown>
  1. I feel its equally important for the api to handle end state for each group {assuming a group can contain both value and text part}.
<span part="group"  ended="true"><span part="day">0</span><span part="day-text">days</span></span><span part="group"  ended="false"><span part="hour">1</span><span part="hour-text">hour</span></span>

How about handling literals if hide is enabled for a group preceding to the last item
example:

Sample String | Code | Sample Output
--- | --- | --- |
0 min and 20 sec | <span part="group" ended="true"><span part="minute">0</span><span part="minute-text"> min <span part="literal"> and </span> </span></span><span part="group" ended="false"><span part="second">20</span><span part="second-text">sec</span></span> | 20 sec

Could amp-mustache be used to format the date? amp-countdown would expose the parts of the date as variables, and mustache would offer flexibility on how to transform those into HTML. Another advantage is that AMP Developers are likely to be familiar with amp-mustache, as it's used in other AMP components.

@andreban That's a great idea! I split the format as described above into 2 proposals and added yours with some samples. Will present both tomorrow in the review meeting. I personally like your proposal much better than the initial format string one.

Didn't get enough time to fully go through the design, will be presenting next design review:

https://docs.google.com/presentation/d/1awrUB2oEZsEC77SteYay0MabAOgGPPDelovtB9nikxk/edit#slide=id.g1f19f58a49_0_51

@ethereal-sandeep there is probably enough to get started with implementation here ( taking the amp-mustache approach ).

@andreban @ethereal-sandeep BTW Our design meetings are open to public if you guys like to attend next one -> #10651

@aghassemi Sure, i will get started with it then and will sure attend the next one.

@ethereal-sandeep I updated the description of this issue with final draft of requirements and format design. We can iterate on the smaller details of the format in the PR.

A small questions about the naming, we ask people to write monthTwoDigits but shorten ā€˜string’ to ā€˜str’ in monthStr? I guess we should go for the full word here, too.

@robinpokorny good point. I changed them here to be word so monthWord (Months) that align nicely with monthName (February) in #10837 .

@ethereal-sandeep @robinpokorny There will be issues like this in the design spec, feel free to use your judgment or raise questions as you work on these.

Agree with Dima that it's probably hard to enumerate all of the possible formats a priori. I suggest we lean on the experience of popular libs for API design [1] or even functionality [2].

[1] iOS's DateFormatter supports locale-specific formatting.
[2] http://blog.stevenlevithan.com/archives/date-time-format looks popular for JS.

@ethereal-sandeep Please note the spec changes after design review yesterday:
Added:
timestamp-ms timestamp-seconds attribute as alternatives to defining the date ( datetime, timestamp-ms, timestamp-seconds is required )
Remove:
convert-to as it does not make sense for this component as counting down to a converted date ends up being the same amount of time anyway.

@choumx Thanks for the pointers, they are relevant to #10837. Replying there.

@aghassemi Noted !

@ethereal-sandeep Just wanted to touch base and see how this is progressing.

@aghassemi working on it. just need a bit more time before i could provide a ref to my wip branch. I will update soon.

@aghassemi current wip branch is here . facing issue with test case and ui update.

Hi @ethereal-sandeep and @aghassemi — I've heard from a few developers recently that they're interested in using this component, so just wanted to check in on how it's going.

Hey

I haven’t been able to work on it much. Still good work is pending. As it’s
my first big component in AMP, I need some help. My code is available at
above provided wip branch.

On Thu, 14 Dec 2017 at 4:50 PM, ericlindley-g notifications@github.com
wrote:

Hi @ethereal-sandeep https://github.com/ethereal-sandeep and @aghassemi
https://github.com/aghassemi — I've heard from a few developers
recently that they're interested in using this component, so just wanted to
check in on how it's going.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/ampproject/amphtml/issues/10385#issuecomment-351683161,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ADAM1ZuiHg3gN9AYYoAA7x2ZO7nEDcNfks5tAQR4gaJpZM4OV_78
.

Thanks @ethereal-sandeep — is there something you specifically could use help with? (is it still related to the test case and ui update you mention above?)

@ethereal-sandeep best way to collaborate would be if you open a Pull Request so it is easier to comment on the code. The first PR does not need to have all the features or tests.

Implemented by #15453

Was this page helpful?
0 / 5 - 0 ratings