JSFiddle - React, Tailwind, and code Playground
by Simon Herteby
HTML
<div id="vue">
<div v-if="topLabel" class="label toplabel" v-html="topLabel"></div>
<template v-for="message, i in messages">
<div class="label" v-if="diff(i)" ref="labels">{{message.date.toDateString()}}</div>
<div class="message">
{{message.date.toLocaleTimeString()}} {{message.text}}
</div>
</template>
</div>
CSS
body{
margin:0;
overflow:hidden;
}
#vue{
max-height:100vh;
overflow:auto;
}
.label{
background:rgba(0,0,0,0.5);
color:white;
padding:5px;
text-align:center;
}
.toplabel{
position:absolute;
width:100%;
top:0px
}
.message{
background:white;
border-radius:99px;
margin:10px;
padding:10px;
}
JavaScript
let messages = []
let hour = 1000 * 60 * 60
for(let i = 0; i < 40; i+= Math.random()){
messages.push({text:'Hello', date:new Date(Date.now() + i * 3 * hour)})
}
new Vue({
el:'#vue',
data:{
messages:messages,
topLabel:undefined
},
methods:{
diff(i){
let current = this.messages[i]
let prev = this.messages[i - 1]
return !prev || (prev.date.toDateString() !== current.date.toDateString())
},
setTopLabel(){
let label = this.$refs.labels.sort((a, b) => a.offsetTop < b.offsetTop).find(el => el.offsetTop < this.$el.scrollTop)
this.topLabel = label && label.innerHTML
}
},
mounted(){
this.setTopLabel()
this.$el.addEventListener('scroll', this.setTopLabel)
}
})