Bootstrap Card ImgOverlay with gatsby-plugin-image not rezizing as expected - css

I have a card component id like to leverage the Bootstrap Card ImgOverlay for, but the image itself is coming gatsby-plugin-image as a GatsbyImage. Below is the component:
const BlogPostCard = (props: BlogPostCardProps) => {
const imageData = getImage(props.imgData)
return (
<Card className={style.blogPostCard}>
<Card.ImgOverlay>
<Card.Body className={style.blogPostCardContent}>
<Card.Title as="h1">{props.title}</Card.Title>
<Card.Subtitle className={style.blogDate}>{props.date}</Card.Subtitle>
<Card.Text>{props.excerpt}</Card.Text>
<Card.Link as={Link} to={props.slug}>Read post.</Card.Link>
</Card.Body>
</Card.ImgOverlay>
<Card.Img className={style.blogPostCardImg} as={GatsbyImage} image={imageData} alt="asdf"/>
</Card>
);
};
where the props.imgData is coming from the following graphql fragment:
node {
frontmatter {
...
image {
childImageSharp {
gatsbyImageData(
placeholder: BLURRED
formats: [AUTO, WEBP]
)
}
...
}
}
Here the scss is as follows:
.blogPostCardContainer {
.blogPostCard {
height: 300px;
.blogPostCardContent {
h1 {
color: $primary-font-color;
text-decoration: underline;
}
p {
color: $primary-font-color;
}
.blogDate {
color: $secondary-font-color;
}
}
.blogPostCardImg {
object-fit: cover;
picture {
opacity: 0.3;
}
}
}
padding-bottom: 2vh;
}
Unfortunately, this is just rendering a card 300px high with the image at full width and no cropping to cover. What id really like is something equivalent to the example given in the object-fit docs: https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit
The card should be dynamic with the props.excerpt length (currently just 300px), and the image should scale and crop to fill the background. Where am I going wrong in my CSS?

This was eventually solved by adding some position values to various container elements to allow one to overflow the parent and the other to govern the parent's height:
js
<Card className={style.blogPostCard}>
<Card.Img className={style.blogPostCardImg} as={GatsbyImage} image={imageData}/>
<Card.ImgOverlay className={style.blogPostCardContent}>
<Card.Body>
<Card.Title as="h1">{props.title}</Card.Title>
<Card.Subtitle>{props.date}</Card.Subtitle>
<Card.Text>{props.excerpt}</Card.Text>
</Card.Body>
</Card.ImgOverlay>
</Card>
css:
.blogPostCardContainer {
.blogPostCard {
position: relative;
overflow-y: hidden;
.blogPostCardImg {
position: absolute;
object-fit: cover;
height: 100%;
}
.blogPostCardContent {
position: relative;
}
}
}

Related

scrolling for overflow-x not working properly

I can scroll on the x axis only by moving the laptop touchpad right to left or by pressing in the scroll button and then moving right to left.Not with normal scroll.
the css is the following:
.row {
color: white;
margin-left: 20px;
}
.row__posters {
display: flex;
overflow-y: hidden;
overflow-x: scroll;
padding: 20px;
}
.row__posters::-webkit-scrollbar {
display: none;
}
.row__poster {
object-fit: contain;
width : 100%;
max-height: 100px;
margin-right: 10px;
transition: transform 450ms;
}
.row__poster:hover {
transform: scale(1.08);
}
.row__posterLarge {
max-height: 250px;
}
.row__posterLarge:hover {
transform: scale(1.09);
}
the Javascipt file is:
import React,{ useState , useEffect} from 'react'
import axios from './axios';
import './Row.css';
const base_url = "https://image.tmdb.org/t/p/original/";
function Row({ title ,fetchUrl,isLargeRow }) {
const [movies, setMovies] = useState([]);
// A snippet of code which runs based on a specific condition
useEffect(() => {
// if we leave the brackets blank [] ,run once when the row loads
and dont run again
async function fetchData() {
const request = await axios.get(fetchUrl);
setMovies(request.data.results);
return request;
}
fetchData();
}, [fetchUrl]);
return (
<div className="row">
<h2>{title}</h2>
<div className="row__posters">
{/* several row_posters */}
{movies.map(movie => (
<img
key={movie.id}
className={`row__poster ${isLargeRow && "row__posterLarge"}`}
src={`${base_url}${
isLargeRow ? movie.poster_path : movie.backdrop_path
}`}
alt={movie.name}
/>
))}
</div>
</div>
)
}
export default Row
I tried alot of solutions but I must be doing something wrong because nothing worked .it could be that I used the proposed code in the wrong department.
Thank you for the help in advance!!

How can i make slider animation?

I need to make the vertical slider animation ( dots and line ) as in this pic
i managed to do the Accordion and the dots but i don't know how i will going to implement it ( i'm using pseudo )
**my accordion component Where i define the logic of my nested accordions as in images based on array of data **
function MultiLevelAccordion({
data,
bodyClass,
headerClass,
wrapperClass,
renderHeader,
renderContent,
}) {
const RootAccordionId = 'parent-0';
const [accordionsStates, setActiveCardsIndex] = useMergeState({});
const onAccordionToggled = (id, activeEventKey) => {
console.log(activeEventKey);
setActiveCardsIndex({
[id]: activeEventKey ? Number(activeEventKey) : activeEventKey
});
};
console.log('data', data);
const accordionGenerator = (data, parentId) => {
return map(data, (item, index) => {
const active = accordionsStates[parentId] === index;
const hasChildren = item.hasOwnProperty('children') && isArray(item.children) && !isEmpty(item.children);
const isRootAccordion = RootAccordionId === parentId;
const isLastNestedAccordion = !isRootAccordion && !hasChildren;
const accordion = (
<Card className={classNames(wrapperClass, {
'nested-root-accordion': !isRootAccordion,
'last-nested-root-accordion': isLastNestedAccordion,
'multi-level-accordion': !isLastNestedAccordion
})}
>
<Accordion.Toggle
{...{ ...item.id && { id: item.id } }}
onClick={() => this}
as={Card.Header}
eventKey={`${index}`}
className={'cursor-pointer d-flex flex-column justify-content-center'}
>
<div className="d-flex justify-content-between align-items-center">
{renderHeader(item, hasChildren)}
<img
style={{
transition: 'all .5s ease-in-out',
transform: `rotate(${active ? 180 : 0}deg)`
}}
src={setIcon('arrow-down')}
className="ml-2"
alt="collapse"
/>
</div>
</Accordion.Toggle>
<Accordion.Collapse eventKey={`${index}`}>
<Card.Body
className={`accordion-content-wrapper ${!hasChildren ? 'accordion-children-body' : ''} ${bodyClass}`}
>
{!hasChildren ? renderContent(item, hasChildren) : (
<Accordion onSelect={activeEventKey => onAccordionToggled(`${parentId}-${index}`, activeEventKey)}>
<Fade cascade top when={active}>
{accordionGenerator(item.children, `${parentId}-${index}`)}
</Fade>
</Accordion>
)}
</Card.Body>
</Accordion.Collapse>
</Card>
);
return isRootAccordion ? accordion : (
<div className={'d-flex align-items-center'}>
{accordion}
<div className="accordion-indicator-wrapper">
<div className="accordion-indicator" id={`indicator-${parentId}-${index}`} />
</div>
</div>
);
});
};
if (!isArray(data)) {
return;
}
return (
<Accordion onSelect={activeEventKey => onAccordionToggled(RootAccordionId, activeEventKey)}>
{accordionGenerator(data, RootAccordionId)}
</Accordion>
);
}
export default MultiLevelAccordion;
the styles used in scss
.faqs-questions-wrapper {
padding: 20px 10px
}
.faqs-q-count {
color: $black-color;
font-size: calc(1rem - 1rem/8)
}
.faqs-q-a-wrapper {
flex-basis: 95%;
}
.faq-child-title {
color: $black-color
}
.nested-root-accordion {
flex-basis: 90%;
}
.accordion-indicator-wrapper {
flex-basis: 10%;
width: 100%;
display: flex;
justify-content: center;
.accordion-indicator {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: $theme-color;
position: relative;
}
}
Any clue?
Thanks in Advance.
React JS is gonna make this easy
The lines expansion will need to be coded based on the height of the box window
For the dropdown container keep the vertical button lines in a separate div than the Accordian
Check out this pen for creating lines between buttons
https://codepen.io/cataldie/pen/ExVGjya
css part:
.status-container{
padding:10px;
margin:10px;
position:relative;
display: inline-block;
}
.bullet{
padding:0px;
margin:0px;
display: inline-block;
z-index: 10;
}
.bullet:before {
content: ' \25CF';
font-size: 5em;
}
.bullet-before{
/*position:relative;
right:-12px;*/
}
.bullet-after{
/*position:relative;
left:-30px;*/
}
.line{
stroke:blue;
stroke-width:0.3em;
padding:0px;
margin:0px;
display: inline-block;
}
.line-on{
stroke:red;
}
.line-off{
stroke:gray;
}
.color-on{
color: red;
}
.color-off{
color: gray;
}
https://codepen.io/emwing/pen/LgzJOx
I think you can use some inspiration here

React Content slider

I am trying to create content slider in React, and to an extent I have succeeded, however I want the content to move horizontally instead of Vertically. Right now all the items are stacked on top of each other which I know is why they cannot work as a horizontal slider, initially I tried using flexbox in order to align the items next to each other but then they are unable to be moved using left or right in the CSS.
What I am currently doing is setting the top of the inner div (Which house the items) to a calculated number of pixels so that it will display the next "Slide". What I have been trying and failing is trying the get the items to be next to each other and the rather than top just change the left/ right of the slider to display the item.
(P.S. I have not added a way to stop the slider over the total number of items, will do that after)
Here is the React Code:
import React, { Component } from "react";
import "../App.css";
class Item extends Component {
constructor(props) {
super(props);
this.state = {
id: 1,
top: "0px",
};
}
onClickSlide = (_) => {
const item = this.state.id;
this.setState({ top: item * 200 * -1 + "px" });
this.setState({ id: item + 1 });
};
render() {
let dang = [
{ title: "Header 1", content: "Lorem ipsum proin gravida" },
{ title: "Header 2", content: "Lorem ipsum proin gravida" },
{ title: "Header 3", content: "Lorem ipsum proin gravida" },
{ title: "Header 4", content: "Lorem ipsum proin gravida" },
];
const item = this.state.id;
let innerStyle = {top: item * 200 * -1 + "px"};
return (
<div className="Outer">
<div className="inner" onClick={this.onClickSlide} style={{ top: this.state.top }}>
{dang.map((data, i) => {
return (
<div className="items">
<h3>{data.title}</h3>
<h3>{data.content}</h3>
</div>
);
})}
</div>
</div>
);
}
}
export default Item;
Here is the CSS:
.Outer {
display: block;
position: relative;
overflow: hidden;
width: 200px;
height: 200px;
}
.inner {
/* display: block; */
position: absolute;
transition: all 0.5s;
}
.items {
display: inline-block;
width: 200px;
height: 200px;
vertical-align: top;
}
Coolness, so with a bit of testing and some other carousel examples I have built my own version. There is still room for improvement but here is the base of it. the idea is to have a super long container were all of the images flex next to each other and by using the CSS property "translate" to move each image left or right depending on the direction clicked.
Below is the React JS example:
export default () => {
const [translate, setTranslate] = useState(0);
const handleClickBtn= (direction) => {
if (direction == "right") {
setTranslate({ translate: translate - 100 });
} else {
setTranslate({ translate: translate + 100 });
}
};
return (
<div className="banner-carousel">
<button
className="carousel-button btn-left"
onClick={(_) => handleClickBtn("left")}
>
Left
</button>
<div className="carousel-container">
<div
className="slide"
style={{ transform: `translateX(${translate}vw)`}}
>
<img className="carousel-image" src="https://www.publicdomainpictures.net/pictures/40000/nahled/random-texture.jpg" />
</div>
<div
className="slide"
style={{ transform: `translateX(${translate}vw)`}}
>
<img className="carousel-image" src="https://www.publicdomainpictures.net/pictures/40000/nahled/random-texture.jpg"/>
</div>
<div
className="slide"
style={{ transform: `translateX(${translate}vw)`}}
>
<img className="carousel-image" src="https://www.publicdomainpictures.net/pictures/40000/nahled/random-texture.jpg"/>
</div>
</div>
<button
className="carousel-button btn-right"
onClick={(_) => handleClickBtn("right")}
>
Right
</button>
</div>
);
};
Here is the SCSS:
.banner-carousel {
height: 720px;
.carousel-button {
cursor: pointer;
position: absolute;
top: 45%;
color: #fff;
z-index: 100;
&.btn-left {
left: 25px;
}
&.btn-right {
right: 25px;
}
}
.carousel-container {
display: flex;
width: 10000px;
.slide {
width: 100vw;
height: 720px;
transition: transform 0.25s linear;
.carousel-image {
width: 100%;
}
}
}
}
Again this still needs to be improved so might come back at a later date and update. If you have any other suggestions please feel free to post!

#media rule not turning off when screen gets larger

I have the following in my CSS file, and it works fine apart from the rule around --md and --sm arent turning off when the screen width goes over 899px.
.ProductThumbnail {
position: relative;
overflow: visible;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
&--md,
&--sm {
display: none;
background-position: 30% top;
#include media('sm', true, true) {
display: block;
}
}
&--lg {
display: none;
background-position: 25% top;
width: 1600px;
#include media('md', true) {
display: block;
}
}
}
The return function in the react component is as follows:
return (
<>
<div
className="ProductThumbnail__bg ProductThumbnail__bg--xs"
style={{
backgroundImage: getURL({
w: 600,
h: 455,
}),
}}
/>
<div
className="ProductThumbnail__bg ProductThumbnail__bg--md"
style={{
backgroundImage: getURL({
h: 455,
}),
}}
/>
<div
className="ProductThumbnail__bg ProductThumbnail__bg--lg"
style={{
backgroundImage: getURL({
w: 2560,
h: 1040,
}),
}}
/>
</>
);
I can see in the dev tools that the rules are being applied as expected for --md and --sm but they dont disappear when the screen gets bigger.
Update, media mixin code:
#mixin media(
$breakpoint,
$is-minimum-only: false,
$is-maximum-only: false) {
#if map_has_key($breakpoint-ranges, $breakpoint) {
$breakpoint-range: get-break-point-range($breakpoint);
$breakpoint: "";
#if length($breakpoint-range) < 2 or $is-minimum-only {
$breakpoint: "(min-width:#{nth($breakpoint-range, 1)})";
} #else if $is-maximum-only {
$breakpoint: "(max-width:#{nth($breakpoint-range, 2)})";
} #else {
$breakpoint: "(min-width:#{nth($breakpoint-range, 1)}) and (max-width:#{nth($breakpoint-range, 2)})";
}
#media screen and #{$breakpoint} {
#content;
}
} #else {
#warn "No registered breakpoint for `#{$breakpoint}`";
}
}
if I understand your mixin correctly, it should generate a media-query with "min" and "max" value if there's no "$is-minimum-only" or "$is-maximum-only" set. So in your case I would remove both "true" settings in this line:
#include media('sm', true, true) {
so it looks like this
#include media('sm') {
Now the third case inside the "#if length($breakpoint-range)" statement should take effect.
Not sure if it even makes sense to set both variables to "true". Because they have a "only" in their names, I suppose only one of them should apply at the same time ;)
I hope that helps.

Can't get buttons to wrap to new line instead of overflowing container

I couldn't get a JSFiddle to work properly with React and some other dependencies, so I hope the link to this Github repo is sufficient for demonstrating the issue:
https://github.com/ishraqiyun77/button-issues/
Basically, a group of buttons is rendered and they should be auto-widened to fill white space and take up the whole row. This works in Chrome, Edge, Safari, and Firefox. It looks like this:
This isn't happening in IE. I've been messing with it for hours and haven't made much progress:
Here is the code, although could clone the repo I posted above:
// component.jsx
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {
Button,
Col,
Modal,
ModalBody,
ModalHeader,
Row
} from 'reactstrap';
import styles from '../assets/scss/app.scss';
class TestPrint extends Component {
constructor(props) {
super(props);
this.state = {
modal: false,
}
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
modal: !this.state.modal
})
}
renderContent() {
let buttons = [];
for (let i = 1; i < 50; i++) {
buttons.push(
<Col key={i}>
<Button
key={i}
className='cuts-btn'
>
{i} - Test
</Button>
</Col>
);
};
return buttons;
}
render() {
return (
<div>
<Button
style={
{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}
}
onClick={this.toggle}
>
Open Modal for Buttons
</Button>
<Modal
size='lg'
isOpen={this.state.modal}
toggle={this.toggle}
className='results-modal'
>
<ModalHeader toggle={this.toggle}>
Button Issues
</ModalHeader>
<ModalBody>
<div className='results-bq-cuts'>
<Row>
{this.renderContent()}
</Row>
</div>
</ModalBody>
</Modal>
</div>
)
}
}
ReactDOM.render(<TestPrint />, document.getElementById('app'));
.results-modal {
max-width: 1200px;
.modal-content {
.modal-body {
margin-left: 13px;
margin-right: 13px;
.results-bq-cuts {
width: 100%;
.col {
padding:2px;
}
.cuts-btn {
font-size: 11px;
padding: 3px;
width: 100%;
box-shadow: none;
}
// .col {
// padding: 2px;
// display: table-cell;
// flex-basis: 100%;
// flex: 1;
// }
// .cuts-btn {
// font-size: 11px;
// padding: 3px;
// width: 100%;
// box-shadow: none;
// }
}
}
}
}
I have all of the <Button> wrapped in <Col> because that should be what is filling the white space by increasing the size of the button.
Thanks for the help!
IE11 doesn't like working out the width of flex items. If you add flex-basis: calc( 100% / 24 ); to .col it works :) Obviously use any width you want, but what I've given replicates the 21 boxes on one line. But essentially flex-basis needs a defined width to work.
​
Or add an extra class to each element (such as col-1 ) This'll also achieve the same thing.

Resources