Symmetrically shrinking Tailwind cards - flexbox

I have four cards aligned in flex raw. Each card has image and text respectively. The gap between each card is 24px (gap-6).
However the image sizes of cards are not equal and when shrinks the proportion/symmetry is not maintained.
Kindly, advice how can I fix this.
Respective code is in playground: https://play.tailwindcss.com/BEc01nvdZj

Here's how I would approach it:
First, we would set each card to take 1/4 of its container by applying w-1/4 to each card. We'll also use a responsive utility (md:) because we want each card to take the full width of the container when the screen is smaller than 768px:
<div class="max-w-sm border bg-white md:w-1/4">
<img src="https://images.unsplash.com/photo-1605546290557-ff57ffe5abcc" alt="" class="h-[12.5rem] w-full object-cover" />
<div class="p-5">
<a href="#">
<h5 class="font-NotoSansGeo mb-2 text-lg font-bold leading-normal md:text-xl">Lorem, ipsum dolor.</h5>
</a>
<p class="mb-3 text-sm font-normal leading-normal text-gray-700 dark:text-gray-400">Lorem ipsum dolor sit amet consectetur adipisicing elit. Laborum asperiores expedita harum eius veritatis minus unde et minima aut numquam!.</p>
</div>
</div>
Now that we have a fixed position for each card, we'll apply some classes to take care of the images width, height, and content.
width: Each image should take the whole width of the container. Therefore we apply w-full.
height: Each image should have a fixed height. This way, we can ensure that the height of each image will be identical. In this example, I set the height to be h-[12.5rem].
content (Docs): We want to make sure that each image will always cover the full size we set (full width and 12.5rem height). This is why we use the object-cover utility. This utility will make sure that the image will cover its container.
We could also use object-fill but it will stretch the image quite a bit.
<img src="https://images.unsplash.com/photo-1605546290557-ff57ffe5abcc" alt="" class="h-[12.5rem] w-full object-cover" />
Tailwind-play
Full Code:
<section class="container mx-auto my-4">
<div class="section-header">
<div class="section-title"><h1 class="font-BPGBannerCaps font-bold tracking-wide">Lorem, ipsum.</h1></div>
<hr class="mb-4 h-px border-0 bg-gray-400 dark:bg-gray-700" />
</div>
<div class="projects w-full md:flex md:gap-6">
<div class="max-w-sm border bg-white md:w-1/4">
<img src="https://images.unsplash.com/photo-1605546290557-ff57ffe5abcc" alt="" class="h-[12.5rem] w-full object-cover" />
<div class="p-5">
<a href="#">
<h5 class="font-NotoSansGeo mb-2 text-lg font-bold leading-normal md:text-xl">Lorem, ipsum dolor.</h5>
</a>
<p class="mb-3 text-sm font-normal leading-normal text-gray-700 dark:text-gray-400">Lorem ipsum dolor sit amet consectetur adipisicing elit. Laborum asperiores expedita harum eius veritatis minus unde et minima aut numquam!.</p>
</div>
</div>
<div class="max-w-sm border bg-white md:w-1/4">
<img src="https://images.unsplash.com/photo-1526628953301-3e589a6a8b74" alt="" class="h-[12.5rem] w-full object-cover" />
<div class="p-5">
<a href="#">
<h5 class="font-NotoSansGeo mb-2 text-lg font-bold leading-normal md:text-xl">Lorem ipsum dolor sit amet consectetur.</h5>
</a>
<p class="mb-3 text-sm font-normal leading-normal text-gray-700 dark:text-gray-400">Lorem ipsum dolor sit amet consectetur adipisicing elit. Sed, repellat dolore. Reprehenderit, modi ullam placeat nam pariatur quas perspiciatis possimus porro ratione? Ad molestias perspiciatis iste ex unde neque enim repellendus sed fugiat consectetur? Voluptatem expedita eum voluptatum explicabo modi.</p>
</div>
</div>
<div class="max-w-sm border bg-white md:w-1/4">
<img src="https://images.unsplash.com/photo-1635695604201-2b718204bccb" alt="" class="h-[12.5rem] w-full object-cover" />
<div class="p-5">
<a href="#">
<h5 class="font-NotoSansGeo mb-2 text-lg font-bold leading-normal md:text-xl">Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum.</h5>
</a>
<p class="mb-3 text-sm font-normal leading-normal text-gray-700 dark:text-gray-400">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Soluta animi atque totam eos nam doloremque iusto qui odio officia doloribus saepe aspernatur dolore eligendi culpa, quos aliquam vel voluptatibus non!</p>
</div>
</div>
<div class="max-w-sm border bg-white md:w-1/4">
<img src="https://images.unsplash.com/photo-1640545232493-9a9b5c88ede4" alt="" class="h-[12.5rem] w-full object-cover" />
<div class="p-5">
<a href="#">
<h5 class="font-NotoSansGeo mb-2 text-lg font-bold leading-normal md:text-xl">Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugiat enim saepe ex. Temporibus, atque nihil.</h5>
</a>
<p class="mb-3 text-sm font-normal leading-normal text-gray-700 dark:text-gray-400">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Repellendus velit voluptate, doloremque asperiores sapiente earum ut obcaecati ipsa necessitatibus itaque similique incidunt. Blanditiis modi nulla pariatur inventore soluta, quo similique quidem quasi perspiciatis nesciunt numquam rerum natus tenetur, consequatur nihil atque, beatae error itaque aspernatur iusto? Architecto vel ea cupiditate.</p>
</div>
</div>
</div>
</section>

Related

Node Project: EJS rendering white space before text retrieved from MongoDB

Good morning.
I am working in my first real development project using Node/MongoDB stack.
Everything is working as expected except by rendering text in EJS engine when I retrieve a string from DB to show in the page: the text is shown with a lot of white spaces in front of it.
I am trimming the text before sending it to the DB, directly in the model. I also tried to trim the text after retrieving it, with no luck.
What makes me believe the problem is with EJS its the fact that the text, on MongoDB doesn't has any trailing white spaces, but it has in the HTML seen in the browser inspect window.
I've searched through a lot of questions related to undesired white spaces, but did not found anything that could help me, so here I am asking for help, which would be very appreciated.
Thank you in advance!
This is how the text is rendered:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus gravida sem libero. Phasellus convallis tellus vitae imperdiet aliquam. Cras sollicitudin maximus augue, sit amet tincidunt felis. Mauris bibendum sollicitudin iaculis. Fusce eget magna tincidunt, porta lorem eu, semper nunc. Morbi at commodo mi. Aliquam feugiat, sem fringilla imperdiet porta, est nisl ultricies mauris, sed finibus orci odio eget quam. Praesent odio ex, suscipit luctus tempus posuere, suscipit ut nisi. Ut feugiat, velit vitae laoreet malesuada, ligula augue vulputate ligula, ut vulputate sapien neque ut dolor. Maecenas congue enim at nisi porttitor cursus. Etiam convallis neque vel urna molestie, et aliquet tortor congue...
This is how it appears in the Inspect Window:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus gravida sem libero. Phasellus convallis tellus vitae imperdiet aliquam. Cras sollicitudin maximus augue, sit amet tincidunt felis. Mauris bibendum sollicitudin iaculis. Fusce eget magna tincidunt, porta lorem eu, semper nunc. Morbi at commodo mi. Aliquam feugiat, sem fringilla imperdiet porta, est nisl ultricies mauris, sed finibus orci odio eget quam. Praesent odio ex, suscipit luctus tempus posuere, suscipit ut nisi. Ut feugiat, velit vitae laoreet malesuada, ligula augue vulputate ligula, ut vulputate sapien neque ut dolor. Maecenas congue enim at nisi porttitor cursus. Etiam convallis neque vel urna molestie, et aliquet tortor congue.
Nullam suscipit dui turpis, non porta odio egestas at. Sed eu ex tristique, facilisis massa sit amet, eleifend erat. Curabitur eu tempus tellus, sed lacinia nunc. Sed aliquam gravida porta. Vivamus eu luctus leo. Vestibulum condimentum arcu sem, vitae vehicula ligula ultrices eget. Fusce pretium molestie pellentesque. Nam ultrices mattis sapien ut consectetur. Cras et vehicula felis. Suspendisse quis egestas nunc, id tempor tellus. Proin placerat accumsan tristique.
</p>
Here is how it is in MongoDB:
{
_id: ObjectId("624c9293e176a46912503d36"),
title: 'Teste Novo Layout',
ages: '3-7',
sensiblePeriod: 'Matemática',
category: 'Visualização de Dados',
theme: 'Testagem',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus gravida sem libero. Phasellus convallis tellus vitae imperdiet aliquam. Cras sollicitudin maximus augue, sit amet tincidunt felis. Mauris bibendum sollicitudin iaculis. Fusce eget magna tincidunt, porta lorem eu, semper nunc. Morbi at commodo mi. Aliquam feugiat, sem fringilla imperdiet porta, est nisl ultricies mauris, sed finibus orci odio eget quam. Praesent odio ex, suscipit luctus tempus posuere, suscipit ut nisi. Ut feugiat, velit vitae laoreet malesuada, ligula augue vulputate ligula, ut vulputate sapien
neque ut dolor. Maecenas congue enim at nisi porttitor cursus. Etiam convallis neque vel urna molestie, et aliquet tortor congue.\r\n' +
' \r\n' +
' \r\n' +
' \r\n' +
' Nullam suscipit dui turpis, non porta odio egestas at. Sed eu ex tristique, facilisis massa sit amet, eleifend e
rat. Curabitur eu tempus tellus, sed lacinia nunc. Sed aliquam gravida porta. Vivamus eu luctus leo. Vestibulum condimen
tum arcu sem, vitae vehicula ligula ultrices eget. Fusce pretium molestie pellentesque. Nam ultrices mattis sapien ut co
nsectetur. Cras et vehicula felis. Suspendisse quis egestas nunc, id tempor tellus. Proin placerat accumsan tristique.',
owned: 'Sim',
picture: 'fatherhood.svg',
date: ISODate("2022-04-05T18:59:49.801Z"),
reviews: [],
user: ObjectId("624c8dfdd0c88d172dfeebee"),
__v: 0
}
This is my Model
//File Requirements
const mongoose = require('mongoose');
const Review = require('./review');
const Schema = mongoose.Schema;
//Local variables
const sensiblePeriods = ['Movimento', 'Linguagem', 'Detalhes', 'Ordem', 'Desenvolvimento dos Sentidos', 'Refinamento dos Sentidos', 'Graça e Cortesia', 'Música e Ritmo', 'Escrita', 'Leitura', 'Matemática']
//Activity Schema
const ActivitySchema = new Schema({
title: {
type: String,
required: true
},
ages: {
type: String,
required: true
},
sensiblePeriod: {
type: String,
//enum limits the options to those inside the array
enum: sensiblePeriods,
required: true
},
category: {
type: String,
},
theme: {
type: String,
},
description: {
type: String,
required: true,
trim: true
},
owned: {
type: String,
required: true,
default: 'Não'
},
picture: {
type: String,
default: 'fatherhood.svg'
},
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
date: {
type: Date,
default: Date.now()
//required: true
},
reviews: [
{
type: Schema.Types.ObjectId,
ref: 'Review'
}
]
})
ActivitySchema.post('findOneAndDelete', async function (doc) {
if (doc) {
await Review.deleteMany({
_id: {
$in: doc.reviews
}
})
}
})
//"Compile" Schema
const Activity = mongoose.model('Activity', ActivitySchema);
//Export module to be used elsewhere
module.exports = Activity;
This is the controller taking the information for the route:
module.exports.details = async (req, res, next) => {
const activity = await Activity.findById(req.params.id).populate({
path: 'reviews',
populate: {
path: 'user'
}
}).populate('user');
if (!activity) {
req.flash('error', 'Atividade não encontrada!')
return res.redirect('/atividades')
}
res.render('atividades/detalhes', { activity });
}
And, finally, this is my EJS file:
<%- include('../partials/head') %>
<div class="row mb-3">
<div class="col-md-6">
<div class="card mb-3">
<img src="/public/img/<%=activity.picture%>" alt="" class="card-img-top">
<div class="card-body">
<h3 class="card-title">
<%=activity.title%>
</h3>
<p class="card-text">
<!-- This is the line which renders the text -->
<%=activity.description%>
<!-- ----------------------------- -->
</p>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item"><b>Dono: </b>
<%=activity.user.username%>
</li>
<li class="list-group-item"><b>Idades: </b>
<%=activity.ages%>
</li>
<li class="list-group-item"><b>Período Sensível: </b>
<%=activity.sensiblePeriod%>
</li>
<li class="list-group-item"><b>Categoria: </b>
<%=activity.category%>
</li>
<li class="list-group-item"><b>Tema: </b>
<%=activity.theme%>
</li>
</ul>
</div>
<% if(currentUser && activity.user.equals(currentUser._id)) {%>
<div class="card mb-3">
<div class="card-body">
<h4 class="card-text mb-3">Área de Risco</h4>
Editar Atividade
<form class="d-inline" action="/atividades/<%=activity._id%>/?_method=DELETE" method="POST">
<button class="btn btn-danger">Excluir Atividade</button>
</form>
</div>
</div>
<% } %>
<p><a class="card-link" href="/atividades">Voltar à todas as atividades</a></p>
</div>
<div class="col-md-6">
<!-- <h2 class="text-center card-title mb-2">Comentários</h2> -->
<% if(currentUser) {%>
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title text-center mb-3">Incluir Comentário
</h4>
<form action="/atividades/<%=activity._id%>/reviews" method="POST">
<div class="row mb-3">
<div class="col">
<div>
<label class="form-label" for="title">Título</label>
</div>
<div>
<input class="form-control" type="text" name="review[title]" id="title" size="26">
</div>
</div>
<!-- <div class="col">
<div class="form-outline">
<div>
<label class="form-label" for="date">Data</label>
</div>
<div>
<input class="form-control" type="date" name="review[date]" id="date">
</div> -->
<!-- </div>
</div> -->
</div>
<div class="mb-3">
<div><label class="form-label" for="body">Comentário</label></div>
<div><textarea class="form-control" name="review[body]" id="body" cols="42" rows="5"></textarea>
</div>
</div>
<button class="btn btn-success">Incluir Comentário</button>
</form>
</div>
</div>
<% } %>
<% const reviews=activity.reviews %>
<% for(let review of reviews) { %>
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">
<%= review.title %>
</h5>
<h6 class="card-subtitle">
Autor: <%= review.user.username %>
</h6>
<% const dbDate=review.date.toISOString()%>
<% const day=dbDate.substring(8,10)%>
<% const month=dbDate.substring(5,7)%>
<% const year=dbDate.substring(0,4)%>
<% const lastUpdated=`${day}/${month}/${year}` %>
<p class="text-secondary">
Última Atualização: <%= lastUpdated %>
</p>
<p>
<%= review.body %>
</p>
<% if(currentUser && review.user.equals(currentUser._id)) {%>
<a href="/atividades/<%= activity._id %>/reviews/<%=review._id%>"
class="btn btn-sm btn-info">Editar Comentário</a>
<form class="d-inline"
action="/atividades/<%= activity._id %>/reviews/<%=review._id%>?_method=DELETE "
method="post">
<button class="btn btn-sm btn-danger">Excluir Comentário</button>
</form>
<% } %>
</div>
</div>
<%}%>
</div>
</div>
</div>
<%- include('../partials/foot') %>

Align sup tag within centered flexbox

I'm struggeling to align the sup tag in the right position within a centered flexbox
.card {
display: flex;
align-items: center;
padding: 2rem 1rem;
border: 1px solid blue;
sup {
color: red;
}
}
<div class="container">
<div class="card">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium, nam reprehenderit eum assumenda illo voluptatibus fugit reiciendis impedit omnis provident dolorum quae itaque quaerat perferendis est? Exercitationem, quas. Blanditiis, dignissimos. Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium, nam reprehenderit eum assumenda illo voluptatibus fugit reiciendis impedit omnis provident dolorum quae itaque quaerat perferendis est? Exercitationem, quas. Blanditiis, dignissimos.<sup>3</sup>
</div>
</div>
Here is my code on codepen:
https://codepen.io/Bizboss/pen/eYBNGVR
<sup>need to be in a <p> tag
.card {
display: flex;
align-items: center;
padding: 2rem 1rem;
border: 1px solid blue;
}
sup {
color: red;
}
<div class="container">
<div class="card">
<p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium, nam reprehenderit eum assumenda illo voluptatibus fugit reiciendis impedit omnis provident dolorum quae itaque quaerat perferendis est? Exercitationem, quas. Blanditiis, dignissimos. Lorem ipsum dolor sit amet consectetur adipisicing elit. Praesentium, nam reprehenderit eum assumenda illo voluptatibus fugit reiciendis impedit omnis provident dolorum quae itaque quaerat perferendis est? Exercitationem, quas. Blanditiis, dignissimos.<sup>3</sup></p>
</div>
</div>

md-card growing bigger than the screen

I hope someone can help me with this piece of code that I have been struggling with for the last couple of hours. I have a grid of cards with a somewhat responsive design. see this pen.My problem is that I do not understand why the 3rd and 4th cards don't fit the screen like the rest of them and instead their width gets increased a lot more than needed.
Just a heads up, I cannot use md-grid so if you can point me to what's wrong with the current code or element distribution I will really appreciate it.
<div ng-controller="MainCtrl" ng-cloak layout flex>
<!-- Some side content -->
<div id="sideContent" hide-xs flex-sm="33" flex-md="30" flex-lg="25" layout="column" class="md-whiteframe-z2" style="z-index: 55">
<p>Some side content</p>
<p>Lorem ipsum dolor sit amet, affert melius disputando ex his. Sit an unum disputando ullamcorper, his ne summo nostrud graecis. At modus nulla vidisse nam, pro et alienum iudicabit repudiandae, mei te dictas dignissim reprehendunt. Vivendum gloriatur
adversarium te nec, liber apeirian tractatos ad pri, choro latine voluptatibus eu est. Ne maluisset liberavisse eos, et luptatum referrentur per.</p>
<p>Lorem ipsum dolor sit amet, affert melius disputando ex his. Sit an unum disputando ullamcorper, his ne summo nostrud graecis. At modus nulla vidisse nam, pro et alienum iudicabit repudiandae, mei te dictas dignissim reprehendunt. Vivendum gloriatur
adversarium te nec, liber apeirian tractatos ad pri, choro latine voluptatibus eu est. Ne maluisset liberavisse eos, et luptatum referrentur per.</p>
<p>Lorem ipsum dolor sit amet, affert melius disputando ex his. Sit an unum disputando ullamcorper, his ne summo nostrud graecis. At modus nulla vidisse nam, pro et alienum iudicabit repudiandae, mei te dictas dignissim reprehendunt. Vivendum gloriatur
adversarium te nec, liber apeirian tractatos ad pri, choro latine voluptatibus eu est. Ne maluisset liberavisse eos, et luptatum referrentur per.</p>
</div>
<md-content style="z-index: 54; position: relative;" flex>
<div layout layout-wrap>
<!-- Custom sized card -->
<div layout flex="35" flex-md="100" flex-xs="100" flex-sm="100">
<md-card flex="noshrink" style="width:300px;height:700px;">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<h3><span>Card 1</span></h3>
</div>
</md-toolbar>
<md-card-content layout="column" layout-padding>Content in card 1</md-card-content>
<span flex></span>
<md-card-icon-actions layout>
<span flex></span>
<md-button aria-label="details">
<span>Details</span>
</md-button>
</md-card-icon-actions>
</md-card>
</div>
<div layout flex flex-md="100" flex-xs="100" flex-sm="100">
<div layout layout-wrap flex>
<!-- Card 2 -->
<md-card flex="noshrink" style="min-width:300px;">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<h3><span>Card 2</span></h3>
</div>
</md-toolbar>
<md-card-content layout="column" layout-padding>
Content in card 2
<md-select placeholder="{{data.currentSelected}}" ng-model="selection">
<md-option ng-value="$index" ng-repeat="text in data.options">{{text.text}}</md-option>
</md-select>
<span>Some random text<br />
More random text, with some more text</span>
</md-card-content>
<span flex></span>
<md-card-icon-actions layout>
<span flex></span>
<md-button aria-label="details">
<span>Details</span>
</md-button>
</md-card-icon-actions>
</md-card>
<!-- tabs -->
<md-card flex="noshrink" style="min-width:300px;">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<h3><span>Card 3</span></h3>
</div>
</md-toolbar>
<md-card-content layout="column" layout-padding>
<md-tabs md-selected="1" md-center-tabs flex>
<md-tab ng-repeat="tab in data.tabs">
<md-tab-label>{{tab.name}}</md-tab-label>
<md-tab-body>
<div style="padding-top:20px;">
<md-list-item class="md-2-line" ng-repeat="content in tab.content">
<img ng-attr-src="http://placehold.it/{{::content.image}}" class="md-avatar" />
<div class="md-list-item-text" layout="column">
<h3>{{::content.title}}</h3>
<p>{{::content.data}}</p>
</div>
<md-icon class="material-icons">
cached
<md-tooltip>Icon 1</md-tooltip>
</md-icon>
<span style="margin-left:5px;"></span>
<md-icon class="material-icons">
cached
<md-tooltip>Icon 2</md-tooltip>
</md-icon>
</md-list-item>
</div>
</md-tab-body>
</md-tab>
</md-tabs>
</md-card-content>
<span flex></span>
<md-card-icon-actions layout>
<span flex></span>
<md-button aria-label="details">
<span>Details</span>
</md-button>
</md-card-icon-actions>
</md-card>
</div>
</div>
</div>
<!-- Lorem -->
<div layout flex>
<div layout flex>
<md-card flex="noshrink" style="min-width:300px;">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<h3><span>Card 4</span></h3>
</div>
</md-toolbar>
<md-card-content layout="column" layout-padding>{{::data.lorem}}</md-card-content>
<span flex></span>
<md-card-icon-actions layout>
<span flex></span>
<md-button aria-label="details">
<span>Details</span>
</md-button>
</md-card-icon-actions>
</md-card>
</div>
</div>
<div layout layout-wrap>
<!-- Card 5 -->
<div layout flex>
<md-card flex="noshrink" style="width:300px;">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<h3><span>Card 5</span></h3>
</div>
</md-toolbar>
<md-card-content layout="column" layout-padding>
<div ng-repeat="content in data.content">{{::content}}</div>
</md-card-content>
<span flex></span>
<md-card-icon-actions layout>
<span flex></span>
<md-button aria-label="details">
<span>Details</span>
</md-button>
</md-card-icon-actions>
</md-card>
</div>
<div layout flex></div>
<!-- Card 6 -->
<div layout flex>
<md-card flex="noshrink" style="width:300px;">
<md-toolbar class="md-hue-2">
<div class="md-toolbar-tools">
<h3><span>Card 6</span></h3>
</div>
</md-toolbar>
<md-card-content layout="column" layout-padding>
<md-subheader class="md-no-sticky">Some addresses {{::data.addresses.expiry_date}}</md-subheader>
<md-list-item class="md-3-line" ng-repeat="address in data.addresses.address">
<md-button class="md-icon-button" href="http://maps.google.com/maps?q=255 Queens Avenue London ON Canada" target="_blank" md-autofocus>
<md-icon class="material-icons">place</md-icon>
<md-tooltip>Open address in Google map</md-tooltip>
</md-button>
<div class="md-list-item-text" layout="column">
<h3>{{::address.description}}</h3>
<p>{{::address.street}}</p>
<p>{{::address.city}}, {{::address.postal_code}}</p>
</div>
</md-list-item>
</md-card-content>
<span flex></span>
<md-card-icon-actions layout>
<span flex></span>
<md-button aria-label="details">
<span>Details</span>
</md-button>
</md-card-icon-actions>
</md-card>
</div>
</div>
</md-content>
</div>

Jade looping through db to build <div>, each one with 3 block of content using bootstrap ? Example provided

I am using this theme http://twbs.github.io/bootstrap/examples/justified-nav/
I want to instantiate the documents of my collections in jade view and (create pagination later on), but my question is about having an HTML or Jade example just to figure out the further process.
this is my div to loop:
<div class="row">
<div class="col-lg-4">
<h2>Safari bug warning!</h2>
<p class="text-danger">As of v7.0.1, Safari exhibits a bug in which resizing your browser horizontally causes rendering errors in the justified nav that are cleared upon refreshing.</p>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn btn-primary" href="#" role="button">View details »</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
<p><a class="btn btn-primary" href="#" role="button">View details »</a></p>
</div>
<div class="col-lg-4">
<h2>Heading</h2>
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa.</p>
<p><a class="btn btn-primary" href="#" role="button">View details »</a></p>
</div>
</div>
Let say I have just 12 documents in my collection, how do I loop trough my collection to create
4 <div class="row"> and each one of these <div class="row"> have 3 <div class="col-lg-4"> and
each <div class="col-lg-4"> have a:
<h2>= product.title
<p> = product.imgurl
<p> = product.description
<p> = prodcuct.url
I know how to route, access the db, display on jade engine...I made simple test
all successful, but to get to the next-level I would appreciate some explanations or a small example.
I resolved myself:
each product, i in products
div
div
h1 = product.title
p = product.imgurl
p = product.description
p = prodcuct.url
I just made a small, quick and dirty example out of your provided informations, I hope it will help you to do the last few steps to get familiar with Jade and co.
First your collection, just a small example (only with 8 examples):
{
products: [{title: 'xyz', imgurl: 'http://www.example.com/img.jpeg',
description: 'more text',
url: 'http://www.example.com/'},
{title: 'abc', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/another'},
{title: 'fgh', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/another'},
{title: 'tgb', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/another'},
{title: 'qwe', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/anotherz'},
{title: 'asd', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/anothery'},
{title: 'hjk', imgurl: 'http://www.example.com/anotherimg.jpeg',
description: 'a lot more text',
url: 'http://www.example.com/anotherx'}]
}
This is what you pass through res.render in your node app.
Next we have your Jade markup, your example is not that wrong, I changed only a few things here:
- for (var i = 0; i < products.length; i += 4)
div.row
- for (var j = i; j < 3+i; j++)
div(class="col-lg-4")
h1= products[j].title
p= products[j].imgurl
p= products[j].description
p= products[j].url
Like you see, I put your <div class="row"> between two loops (I used for loops here, it would be easier if you pass your data in an other way. What I try to say: This example is not fail safe, e.g. if you don't have data that has 3 cols you will get an error like Cannot read property 'title' of undefined - so here you have to set exceptions), so we don't get more than one per 3 iterations, your example would produce one div per iteration.
A class can be added by a dot. For example div.yourClass or just with div(class="yourClass" style="..." whatever="...").
Next we have the loop, after that given <div class="col-lg-4 "> for your collection data. Your data can be displayed by either tag= var or tag #{var}.
The rest should be simple to guess.
This will produce following HTML code:
<div class="row">
<div class="col-lg-4">
<h1>xyz</h1>
<p>http://www.example.com/img.jpeg</p>
<p>more text</p>
<p>http://www.example.com/</p>
</div>
<div class="col-lg-4">
<h1>abc</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/another</p>
</div>
<div class="col-lg-4">
<h1>fgh</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/another</p>
</div>
</div>
<div class="row">
<div class="col-lg-4">
<h1>qwe</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/anotherz</p>
</div>
<div class="col-lg-4">
<h1>asd</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/anothery</p>
</div>
<div class="col-lg-4">
<h1>hjk</h1>
<p>http://www.example.com/anotherimg.jpeg</p>
<p>a lot more text</p>
<p>http://www.example.com/anotherx</p>
</div>
</div>
You see the <p> tag for links makes here not that much sense, but you can easily change them to an <a> tag, it is always the same procedure.
Important, in your Jade markup, is the right indentation, everything shifted is between the opening tag and the close tag.
So the loop is in div row, the data in your cols.

Is it possible to create a pinterest-like layout with Bootstrap only?

I am trying to the get my head around this for quite some time now:
Is it possible to create a pinterest Layout with Twitter Bootstrap only?
I know there are jQuery Plugins like Masonry, but is there no way without them?
Thanks
Found a (free) template at http://bragthemes.com/demo/pinstrap/. It's supposed to have all you are asking for. Haven't had time to check it out, though.
Edit 2016-03-15: Bootstrap 4 allows this out of the box here. It's still in alpha, but we're getting there.
Found this solution, works within bootstrap (works even without defining column sizes), doesn't require javascript -- I snapped it into a project and it works beautifully:
http://www.bootply.com/118335
Bless you #katiejones!
EDIT: This is now out of the box in boostrap 4 http://v4-alpha.getbootstrap.com/components/card/#card-columns
Sure Thing. Took me a while to work out. Hope this helps!
Apologies for the code dump but its necessary to show the grid working.
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/masonry.js"></script>
<script type="text/javascript" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/imagesLoaded.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css" integrity="sha384-aUGj/X2zp5rLCbBxumKTCw2Z50WgIr1vs/PFN4praOTvYXWlVyh2UtNUU0KAUhAX" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>
</head>
<div class="container">
<div class="row masonry-container">
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipsum dolosit amet, consectetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipdolor sit amet, consectetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipsum dolor ctetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipdolor sit amet, consectetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eliLorem ipsum dolor sit amet, consectetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
<div class="col-xs-6 col-sm-3 col-md-3 item">
<div class="thumbnail">
<img src="http://lorempixel.com/150/200/abstract" alt="">
<div class="caption">
<h3>Thumbnail label</h3>
<p>Lorem ipsumLorem ipsum dolor ctetur adipisicing eli dolor sit amet, consectetur adipisicing elit. </p>
</div>
</div>
</div><!--/.item -->
</div> <!--/.masonry-container -->
</div><!--/.tab-panel -->
<style type="text/css">
body {
padding-top: 50px;
}
.main-container {
padding: 10px 15px;
}
.p {
text-align: center;
}
</style>
<script type="text/javascript">
/* Demo Scripts for Making Twitter Bootstrap 3 Tab Play Nicely With The Masonry Library
* on SitePoint by Maria Antonietta Perna
*/
//Initialize Masonry inside Bootstrap 3 Tab component
(function( $ ) {
var $container = $('.masonry-container');
$container.imagesLoaded( function () {
$container.masonry({
columnWidth: '.item',
itemSelector: '.item'
});
});
//Reinitialize masonry inside each panel after the relative tab link is clicked -
$('a[data-toggle=tab]').each(function () {
var $this = $(this);
$this.on('shown.bs.tab', function () {
$container.imagesLoaded( function () {
$container.masonry({
columnWidth: '.item',
itemSelector: '.item'
});
});
}); //end shown
}); //end each
})(jQuery);
</script>
Yes, it is possible but with some limitations.
Principle
Each column is a div (or section depending upon the meaning of your layout)
Within each column each tile is also be a div, or img etc. depending upon your design.
Practice
To make the columns you can use the following various techniques:
float the columns
display: inline-block the columns
Use the new flexible box API (non-standard implementations are creeping into modern browsers)
Use the new grid positioning API (although I'd avoid this for now as it's not supported hardly at all)
Then place various tiles (divs) in each column. Again, depending upon your design/layout you could replace the column-divs with uls, and have a list of tiles (lis). I can't speak as to whether that is semantically correct for your design.
Limitations
Resizing the Pinterest page maintains the general position of most elements i.e. elements at the top of a column generally stays near the top, even when the number of columns is adjusted for the browser width - the pure CSS solution won't do that out of the box.
Work-Arounds
While not a perfect solution, you can use media queries to influence the position of various elements.
With some time, one could get pretty close to the Pinterest layout - that said, there's probably a good reason they chose to implement said layout with JavaScript.
I know my answer is late. but just wanted this common question to be up dated. I found out 3 latest implementations.
isotope. Found this on bootstrap website. Works well with infinite-scroll to build infinite scroll web pages too.
Salvattore. This is achived with pure CSS and JS. JS is only used to pull data.
masonry.desandro.com. This is a JS intensive implementation. but it has its own features.
Since Bootstrap 4, the .card-columns class is available.
Specifications in there documentation here. It makes a nice Pinterest-like grid. 😌
<div class="card-columns">
<div class="card" id="card1"></div>
<div class="card" id="card2"></div>
<div class="card" id="card3"></div>
<div class="card" id="card4"></div>
<div class="card" id="card..."></div>
</div>
About the number of columns, though, I had trouble adapting it to different screen sizes. I finally managed to do it with :
#media (max-width: 575.98px){
.card-columns {
column-count: 1; }
}
#media (min-width: 576px){
.card-columns {
column-count: 2; }
}
#media (min-width: 768px){
.card-columns {
column-count: 3; }
}
#media (min-width: 992px){
.card-columns {
column-count: 4; }
}
#media (min-width: 1200px){
.card-columns {
column-count: 4; }
}
There we have a stuff named: bootstrap-waterfall:
http://mystist.github.io/bootstrap-waterfall/
But in fact, this plugin does not need bootstrap as it's dependencies. It's depends on whether you want to use bootstrap as your pin's markups or just style it yourself.
<div class="card-deck">
<div class="card">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-block">
<h4 class="card-title">Card title</h4>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
</div>
<div class="card">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-block">
<h4 class="card-title">Card title</h4>
<p class="card-text">This card has supporting text below as a natural lead-in to additional content.</p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
</div>
<div class="card">
<img class="card-img-top" src="..." alt="Card image cap">
<div class="card-block">
<h4 class="card-title">Card title</h4>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This card has even longer content than the first to show that equal height action.</p>
</div>
<div class="card-footer">
<small class="text-muted">Last updated 3 mins ago</small>
</div>
</div>
</div>
For everyone who dont want want to go through the hassle of cross browser compatibility, here is a PHP solution. Assuming you have your data in an array,
<?php $iColumns = 4;?>
<?php for($i=0; $i < $iColumns; ++$i):?>
<div class="span3">
<?php
$j=$i;
while( isset( $aData[$j] ) ):
$oItem = $aData[$j]
?>
<div class="thumbnail" style="margin-top:10px;">
<a href="">
<img src="" alt=""/>
</a>
<h3>title</h3>
<p>caption</p>
</div>
<?php
$j=$j+$iColumns;
endwhile;?>
</div>
<?php endfor;?>

Resources