Reputation: 6204
I have items dynamically added where each item uses CSS Grid Layout. This is what my Grid Looks like
As you can see the first column in the first grid does not match with the first column s width in the second grid. How do I make them the same?
HTML
<div id="app">
<div class="list_item" v-for="item in sortedItems" :key="item.feedItemId">
<div class="news_time">{{getFormattedDate(item.pubdate)}}</div>
<div class="news_title">{{item.title}}</div>
<div class="news_link"><span class="news_link_text">{{getHostFromUrl(item.link)}}</span></div>
<div class="news_stats" :class="isStatShown(item) ? '' : 'hide'">
<div class="likes"><i class="fa fa-thumbs-up"></i><span class="stats_text">{{item.likes || 0}}</span></div>
<div class="dislikes"><i class="fa fa-thumbs-down"></i><span class="stats_text">{{item.dislikes || 0}}</span></div>
<div class="bullish"><i class="fa fa-arrow-up"></i><span class="stats_text">{{item.bullish || 0}}</span></div>
<div class="bearish"><i class="fa fa-arrow-down"></i><span class="stats_text">{{item.bearish || 0}}</span></div>
<div class="comments"><i class="fa fa-comment-alt"></i><span class="stats_text">{{item.comments || 0}}</span></div>
</div>
<div class="news_tags">
<div class="news_tag" v-for="tag in item.tags" :key="item.tag">{{tag}}</div>
</div>
</div>
</div>
CSS
@import url('https://fonts.googleapis.com/css?family=Noto+Sans&display=swap');
/**
There are 2 CSS Grids to acheive this layout?
It can be achieved in 1 layout so why 2?
Because stats are shown conditionally.
Meaning if all are 0 we dont show the whole row!
The outer CSS Grid has 3 rows and 4 columns
Row 1
time title title and tag
Row 2
time link link and tag
Row 3
time stats <empty-cell> and tag
The row containing stats is set to auto as it collapses when all stats are 0
*/
* {
padding: 0;
margin: 0;
box-sizing: border-box;
line-height: 1.6;
font-family: 'Noto Sans', sans-serif;
}
.news_time {
grid-area: time;
}
.news_title {
grid-area: title;
}
.news_link {
grid-area: link;
}
.news_stats {
grid-area: stats;
}
.news_tags {
grid-area: tags;
}
.list_item {
display: grid;
grid-template-areas:
"time title title tags"
"time link link tags"
"time stats . tags";
grid-template-rows: 1fr auto auto;
grid-template-columns: auto auto 1fr auto;
align-items: center;
}
.likes {
grid-area: likes;
}
.dislikes {
grid-area: dislikes;
}
.bullish {
grid-area: bullish;
}
.bearish {
grid-area: bearish;
}
.comments {
grid-area: comments;
}
/**
This is our second CSS Grid
If stats are not available, this whole grid will be hidden.
It has only 1 row and 5 columns
Row 1
Likes Dislikes Bullish Bearish and Comments
It adds a gap to separate the adjacent cells
*/
.news_stats {
display: grid;
grid-template-areas:
"likes dislikes bullish bearish comments";
grid-rows: 1fr;
grid-columns: 1fr 1fr 1fr 1fr 1fr;
grid-gap: 0.75rem;
gap: 0.75rem;
}
/**
Spacing
*/
.list_item {
border: 1px solid #eef;
}
.news_stats {
font-size: 0.75rem;
opacity: 0.4;
margin: 0.3rem 0;
}
.news_link {
font-size: 0.85rem;
opacity: 0.6;
}
.stats_text {
display: inline-block;
margin-left: 0.3rem;
}
.news_time {
font-size: 0.75rem;
margin: 1rem;
opacity: 0.75;
}
.news_tags {
margin: 1rem;
font-size: 0.75rem;
opacity: 0.75;
}
/**
Use this class to hide anything that must not be shown
*/
.hide {
display: none;
}
JS
const mapState = Vuex.mapState;
const mapMutations = Vuex.mapMutations;
const mapGetters = Vuex.mapGetters;
const storeObject = {
state() {
return {
items: {
"54069cf1-7a6a-d356-2a7a-3a4d5cf82191": {
feedItemId: "54069cf1-7a6a-d356-2a7a-3a4d5cf82191",
pubdate: new Date("2019-10-1 16:06:40+05:30"),
link:
"https://www.cryptovibes.com/blog/2019/09/30/cardano-technology-will-be-used-by-new-balance-to-combat-counterfeits/",
title:
"Cardano Technology will be Used by New Balance to Combat Counterfeits",
author: "Ali Raza",
feed_id: 98,
likes: 3,
dislikes: 1,
bullish: 6,
bearish: 3,
comments: 5,
tags: ["ADA"]
},
"c68ef754-da41-b4fd-eb3a-150735fc0535": {
feedItemId: "c68ef754-da41-b4fd-eb3a-150735fc0535",
pubdate: new Date("2019-09-30 02:50:43+05:30"),
link:
"https://ethereumworldnews.com/jp-morgan-bitcoin-price-crash-8000/",
title: "Top Airdrops You Should Look Out for in October 2019",
author: "Ogwu Osaemezu Emmanuel",
feed_id: 98,
tags: ["BTC", "ETH"]
},
"a68ef754-da41-b4fd-eb3a-150735fc0535": {
feedItemId: "a68ef754-da41-b4fd-eb3a-150735fc0535",
pubdate: new Date("2019-09-30 02:50:43+05:30"),
link:
"https://ethereumworldnews.com/jp-morgan-bitcoin-price-crash-8000/",
title: "JP Morgan on What Caused Bitcoin Price Crash to $8,000",
author: "Nick Chong",
feed_id: 98,
likes: 0,
dislikes: 8,
bullish: 0,
bearish: 3,
comments: 8,
tags: ["BTC", "ETH", "EOS"]
}
}
};
},
getters: {
sortedItems(state) {
return Object.values(state.items).sort((a, b) => b.pubdate - a.pubdate);
}
}
};
const store = new Vuex.Store(storeObject);
const timeSince = Vue.mixin({
methods: {
timeSince(date) {
var seconds = Math.floor((new Date() - date) / 1000);
var interval = Math.floor(seconds / 31536000);
if (interval > 1) {
return interval + " y";
}
interval = Math.floor(seconds / 2592000);
if (interval > 1) {
return interval + " M";
}
interval = Math.floor(seconds / 86400);
if (interval > 1) {
return interval + " d";
}
interval = Math.floor(seconds / 3600);
if (interval > 1) {
return interval + " h";
}
interval = Math.floor(seconds / 60);
if (interval > 1) {
return interval + " m";
}
return Math.floor(seconds) + " s";
}
}
});
const viewModel = new Vue({
el: "#app",
mixins: [timeSince],
computed: {
...mapState(["items"]),
...mapGetters(["sortedItems"])
},
methods: {
getHostFromUrl(url) {
return new URL(url).host.replace(/^www\./, "");
},
getFormattedDate(date) {
return this.timeSince(date);
},
isStatShown(item) {
return item.likes || item.dislikes || item.bullish || item.bearish || item.comments;
}
},
store
});
Upvotes: 1
Views: 453
Reputation: 116
You can do that like this:
.news_time {
font-size: 0.75rem;
margin: 1rem;
opacity: 0.75;
width: 2rem;
}
Upvotes: 1