Skip to content

Commit 66194a6

Browse files
toadkickertmorehouse
authored andcommitted
feat(card): support left and right image placement (#1981)
feat(card): support left and right image placement
1 parent 6d33cae commit 66194a6

File tree

5 files changed

+96
-15
lines changed

5 files changed

+96
-15
lines changed

docs/assets/css/styles.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,12 @@ pre.editable.live:after {
101101
min-height: 10rem;
102102
background-color: rgba(255, 0, 0, .1);
103103
}
104+
105+
.card-img-left {
106+
border-top-left-radius: calc(0.25rem - 1px);
107+
border-bottom-left-radius: calc(0.25rem - 1px);
108+
}
109+
.card-img-right {
110+
border-top-right-radius: calc(0.25rem - 1px);
111+
border-bottom-right-radius: calc(0.25rem - 1px);
112+
}

src/components/card/README.md

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ card is changed.
100100

101101
```html
102102
<div>
103+
<h4>Top and Bottom</h4>
103104
<b-card-group deck>
104105
<b-card img-src="https://placekitten.com/1000/300"
105106
img-alt="Card image"
@@ -114,10 +115,38 @@ card is changed.
114115
<p class="card-text">
115116
Some quick example text to build on the card and make up the bulk of the card's content.
116117
</p>
117-
</b-card>
118-
</b-card-group>
118+
</b-card>
119+
</b-card-group>
120+
<br>
121+
<h4>Left and Right (or Start and End)</h4>
122+
<b-card img-src="https://placekitten.com/300/300"
123+
img-alt="Card image"
124+
img-left
125+
class="mb-3">
126+
<p class="card-text">
127+
Add to your css: <br>
128+
<code>
129+
.card-img-left { <br>
130+
&nbsp;&nbsp;border-top-left-radius: calc(0.25rem - 1px); <br>
131+
&nbsp;&nbsp;border-bottom-left-radius: calc(0.25rem - 1px); <br>
132+
}
133+
</code>
134+
</p>
135+
</b-card>
136+
<b-card img-src="https://placekitten.com/300/300"
137+
img-alt="Card image"
138+
img-right>
139+
<p class="card-text">
140+
Add to your css: <br>
141+
<code>
142+
.card-img-right { <br>
143+
&nbsp;&nbsp;border-top-right-radius: calc(0.25rem - 1px); <br>
144+
&nbsp;&nbsp;border-bottom-right-radius: calc(0.25rem - 1px); <br>
145+
}
146+
</code>
147+
</p>
148+
</b-card>
119149
</div>
120-
121150
<!-- card-img-1.vue -->
122151
```
123152

@@ -126,7 +155,7 @@ Place the image in the background of the card by setting the boolean prop `overl
126155
```html
127156
<div>
128157
<b-card overlay
129-
img-src="https://picsum.photos/900/250/?image=36"
158+
img-src="https://picsum.photos/900/250/?image=3"
130159
img-alt="Card Image"
131160
text-variant="white"
132161
title="Image Overlay"

src/components/card/card-img.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { mergeData } from 'vue-functional-data-merge'
1+
import {mergeData} from 'vue-functional-data-merge'
22

33
export const props = {
44
src: {
@@ -18,6 +18,32 @@ export const props = {
1818
type: Boolean,
1919
default: false
2020
},
21+
left: {
22+
type: Boolean,
23+
default: false
24+
},
25+
start: {
26+
type: Boolean,
27+
default: false
28+
// alias of 'left'
29+
},
30+
right: {
31+
type: Boolean,
32+
default: false
33+
},
34+
end: {
35+
type: Boolean,
36+
default: false
37+
// alias of 'right'
38+
},
39+
height: {
40+
type: String,
41+
default: null
42+
},
43+
width: {
44+
type: String,
45+
default: null
46+
},
2147
fluid: {
2248
type: Boolean,
2349
default: false
@@ -27,20 +53,24 @@ export const props = {
2753
export default {
2854
functional: true,
2955
props,
30-
render (h, { props, data, slots }) {
56+
render (h, {props, data, slots}) {
3157
let staticClass = 'card-img'
3258
if (props.top) {
3359
staticClass += '-top'
60+
} else if (props.right || props.end) {
61+
staticClass += '-right'
3462
} else if (props.bottom) {
3563
staticClass += '-bottom'
64+
} else if (props.left || props.start) {
65+
staticClass += '-left'
3666
}
3767

3868
return h(
3969
'img',
4070
mergeData(data, {
4171
staticClass,
42-
class: { 'img-fluid': props.fluid },
43-
attrs: { src: props.src, alt: props.alt }
72+
class: {'img-fluid': props.fluid},
73+
attrs: {src: props.src, alt: props.alt, height: props.height, width: props.width}
4474
})
4575
)
4676
}

src/components/card/card.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default {
4040
// The order of the conditionals matter.
4141
// We are building the component markup in order.
4242
let childNodes = []
43+
let staticClass = 'card'
4344
const $slots = slots()
4445
let img = props.imgSrc
4546
? h(CardImg, {
@@ -50,13 +51,15 @@ export default {
5051
)
5152
})
5253
: null
53-
54-
if (img) {
55-
// Above the header placement.
56-
if (props.imgTop || !props.imgBottom) {
57-
childNodes.push(img)
54+
if (img && !props.imgBottom) {
55+
childNodes.push(img)
56+
if (props.imgLeft || props.imgStart) {
57+
staticClass += ' flex-row'
58+
} else if (props.imgRight || props.imgEnd) {
59+
staticClass += ' flex-row-reverse'
5860
}
5961
}
62+
6063
if (props.header || $slots.header) {
6164
childNodes.push(
6265
h(CardHeader, { props: pluckProps(headerProps, props) }, $slots.header)
@@ -74,15 +77,15 @@ export default {
7477
h(CardFooter, { props: pluckProps(footerProps, props) }, $slots.footer)
7578
)
7679
}
80+
7781
if (img && props.imgBottom) {
78-
// Below the footer placement.
7982
childNodes.push(img)
8083
}
8184

8285
return h(
8386
props.tag,
8487
mergeData(data, {
85-
staticClass: 'card',
88+
staticClass: staticClass,
8689
class: {
8790
[`text-${props.align}`]: Boolean(props.align),
8891
[`bg-${props.bgVariant}`]: Boolean(props.bgVariant),

src/components/card/card.spec.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ describe('card', async () => {
8585
})
8686
})
8787

88+
it('should add flex-row to a img-left or img-right image', async () => {
89+
const { app } = window
90+
const node = app.$refs['img_card']
91+
const childNodes = [...node.childNodes]
92+
const imgEl = childNodes.find(el => el.tagName && el.tagName === 'IMG')
93+
94+
expect(imgEl).toBeDefined()
95+
expect(imgEl.classList).toEqual(expect.objectContaining(/^flex-row/))
96+
})
97+
8898
it("should use the 'tag' for element tag", async () => {
8999
const { app: { $refs } } = window
90100
const $titleCard = $refs.card_group.querySelector('#title-tag-test')

0 commit comments

Comments
 (0)