creating overlapping user icons - css

I'm trying to create a a component that overlaps over the user icons just as shown in the photo. I've seen this being used on google. If I have a list of user icons, how do I overlap them over each other?
I want something like this .
<template>
<div >
<ul>
<li v-for="user in userList" :key="user.key">
<user-icon-component :name="user.name" :image="user.picture"></user-icon-component>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "UserList",
props: {
userList: {
type: Object,
default: null,
},
},
};
</script>
<style>
</style>

The icon component is just an <img> tag with a user prop:
Vue.component('user-icon-component', {
props: ['user'],
template: `
<img :src="user.picture" width="32" height="32" />
`
})
Give the <li>s position: absolute and the <ul> position: relative to pull them out of the normal document flow. Set the left position on each <li> as a calculation from the index of the loop:
<ul class="icon-container">
<li v-for="(user, key, i) in userList" :key="user.key"
class="icon" :style="{ left: `${i * 20}px` }">
<user-icon-component :user="user"></user-icon-component>
</li>
</ul>
Here's a demo:
Vue.component('user-icon-component', {
props: ['user'],
template: `
<img :src="user.picture" width="32" height="32" />
`
})
/***** APP *****/
new Vue({
el: "#app",
data() {
return {
userList: {
'Bob': { name: 'Bob', key: 1, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084430.svg' },
'Mary': { name: 'Mary', key: 2, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084431.svg' },
'Paul': { name: 'Paul', key: 3, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084452.svg' },
}
}
},
});
.icon-container {
position: relative;
}
.icon {
position: absolute;
}
ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul class="icon-container">
<li v-for="(user, key, i) in userList" :key="user.key"
class="icon" :style="{ left: `${i * 20}px` }">
<user-icon-component :user="user"></user-icon-component>
</li>
</ul>
</div>

I liked the idea in your question and took it as a challenge for myself and here is the result:
vue overlapping avatars component
basically the approach I took was to use the component's props as style in style binding. there are some scoped style as well but I think they can be set in the style binding as well if needs be (probably the code could be cleaner).
user prop is an array of objects that contains this property: img: 'imageURL' and using a v-for on a div element with:
:style="{ backgroundImage: `url(${user.img})`}"
we can set the images.
as for the overlapping part, divs have position: relative and using the index of v-for, the style binding becomes like this:
:style="{backgroundImage: `url(${user.img})`, left: `-${i*15}px`}"
which shifts every element to the left by 15px except for the first one.
here is the image of the final result:
Thanks for your question, it was fun :)

Related

React how to style an anchor tag as a tile that remains selected when clicked on it

buttonI need to style the anchor tag to look like a rectangular tile (which I'm already doing) and when clicked on that tile/anchor tag, I need to do the following 2 things:
Keep it selected and highlight it with Green colour.
On selection or change in selection between TILE-1, TILE-2 and TILE-3, I need to fetch the value of the text in the input field.
Can someone please share any guidelines on how this can be done, please?
const showTile = (): ReactElement => {
<ul className="tileList">
<li>
<button href="#Tile1" class="tile" >
TILE-1
</button >
</li>
<li>
<button href="#Tile2" class="tile">
TILE-2
</button >
</li>
<li>
<button href="#Tile3" class="tile">
TILE-3
</button >
</li>
</ul>
};
const showTextBox = (): ReactElement => {
<input type="text" value="">
};
const [selectedTile, setSelectedTile] = useState("");
const [textVal, setTextVal] = useState("");
return (<div> {showTile} {showTextBox} </div>);
ul,
li {
list-style: none;
}
.tileList > li button {
color: grey;
background-colour: yellow;
border: 1px solid #ffffff;
padding: 10px 15px;
font-size: 13px;
}
use dynamic class for selected tie and a variable for assigned to it
and for changing value make a 2D array and insert the ties value in there then a simple function for changing ties values
its like a puzzle app search for puzzle functions to see more
I solved it like this.
state ={
selected: false
}
selectedHandle = () => {
const {selected} = this.state
this.setState({selected: true})
}
<li onClick={() => this.selectedHandle()}>
<a href="#Tile1" class={{selected === true ? "active" : "passive"}} >
TILE-1
</a>
</li>
for fetching the value you can following this question how to use event.target.value in li

vuedraggable custom style for each individual item

I need to have each vuedraggable item to have different styling in the wrapper tag (for example based on the element's index) like so:
<div class="wrapper">
<div class="grid_item" style="grid-row: 1">
I am Item 1
</div>
<div class="grid_item" style="grid-row: 2">
I am Item 2
</div>
<div class="grid_item" style="grid-row: 3">
I am Item 3
</div>
</div>
I know this is a very simple example that doesn't really need the index but suppose a more complex scenario where it is necessary to have access to the index in the draggable component (not its child template).
Suppose the current component looks like this:
<template>
<div class="wrapper">
<draggable
:list="items"
class="grid_item"
item-key="name">
<template #item="{ element }">
I am {{ element.name }}
</template>
</draggable>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
components: {
draggable,
},
data() {
return {
items: [
{
name: 'Item 1'
},
{
name: 'Item 2'
},
{
name: 'Item 3'
},
],
}
},
methods: {
rowForItem(index) {
return `grid-row: ${index + 1}`;
}
},
}
</script>
<style>
.wrapper {
display: grid;
}
.grid_item {
background-color: gray;
}
</style>
How can I make use of the rowForItem method here?

css3 transtion not working with v-for in vue2

I use transtion in vue2. I added transition in css. Vue template show two box. One way use v-for and array, another way is use variable. btn2 is effective but btn1 not.
<style lang="sass">
.item
width: 120px
height: 120px
background-color: bisque
transition: margin-left 500ms
</style>
<template>
<div>
<div class="item" v-for="item in list" :key="item.index" :style="{marginLeft: item.index + 'px'}">{{ item.value }}</div>
<div class="item" :style="{marginLeft: left + 'px'}">123</div>
<button #click="addone">btn1</button>
<button #click="addtwo">btn2</button>
</div>
</template>
<script>
export default {
name: 'Heap',
data() {
return {
left: 100,
list: [
{
value: 12,
index: 10
}
]
}
},
methods: {
addone() {
this.list[0]['index']+=10
},
addtwo() {
this.left+=10
}
}
}
</script>
You are using the code :key="item.index" on your first div. Your code then updates that same index.
When a key's value changes, the component it is attached to re-renders. You are not seeing the animation occur because instead of dynamically incrementing the CSS, you are effectively just re-rendering the element with the new CSS.
The purpose of a key is to help Vue keep track of the identity of a given node in a list. It lets Vue know which nodes it can keep and patch up and which ones need to be rendered again.
You should use a static, non-changing value as a key where possible. In the following example I have added an id property to your object and used that as the key.
<style lang="sass">
.item
width: 120px
height: 120px
background-color: bisque
transition: margin-left 500ms
</style>
<template>
<div>
<div
v-for="item in list"
:key="item.id"
class="item"
:style="{marginLeft: item.index.toString() + 'px'}"
>
{{ item.value }}
</div>
<div class="item" :style="{marginLeft: left.toString() + 'px'}">123</div>
<button #click="addone">btn1</button>
<button #click="addtwo">btn2</button>
</div>
</template>
<script>
export default {
name: 'Example',
data() {
return {
left: 100,
list: [
{
id: '1',
value: 12,
index: 10,
},
],
};
},
methods: {
addone() {
this.list[0].index += 10;
},
addtwo() {
this.left += 10;
},
},
};
</script>

Hide nav button in react-material-ui-carousel

I've just implemented the react material ui carousel, and it was pretty straightforward, the only thing i didn't catch, is how to hide buttons and show them only on over.
I noticed the props navButtonsAlwaysVisible and set it to false but it isn't enough.
Should i implement my own logic for that, or maybe I'm just missing something?
here's the component code:
import styles from '../../styles/Testimonial.module.scss'
import Image from 'next/image'
import Carousel from 'react-material-ui-carousel'
const Testimonial = _ => {
const items = [
{
imageUrl: "/png/image0.webp",
feedback: "feedback0",
name: "name0",
location: "location0"
},
{
imageUrl: "/png/image1.jpeg",
feedback: "feedback1",
name: "name1",
location: "location1"
}
]
return (
<div id="customers" className={`section ${styles.testimonial}`}>
<h2 className={`title ${styles.title}`}>Clientes Felizes</h2>
<span className={"separator"}> </span>
<Carousel
className={styles.carousel}
autoPlay={true}
stopAutoPlayOnHover={true}
interval={5000}
animation={"slide"}
swipe={true}
navButtonsAlwaysVisible={false}
navButtonsProps={{
style: {
backgroundColor: "#8f34eb",
opacity: 0.4
}
}}
>
{
items.map( (item, i) => <Item key={i} item={item} /> )
}
</Carousel>
</div>
)
}
function Item(props)
{
return (
<article className={styles.testimonial__card}>
<div className={styles.testimonial__photo_container}>
<Image
className={styles.testimonial__photo}
src={props.item.imageUrl}
alt="Testimonial"
width={312}
height={300}
/>
</div>
<p className={styles.testimonial__copy}>{props.item.feedback}</p>
<span className={styles.testimonial__name}>{props.item.name}</span>
<span className={styles.testimonial__city}>{props.item.location}</span>
</article>
)
}
export default Testimonial;
there's a prop called navButtonsAlwaysInvisible
navButtonsAlwaysInvisible={true}
You can try using Custom CSS for your purpose. Based on the current rendered markup,
.jss6 {
opacity: 0;
transition: all ease 1000ms; /* So that it does not disappear quickly */
}
You can define the hover for the parent so that it displays only when the parent container is hovered on:
.jss1.Testimonial_carousel__3rny3:hover .jss6 {
opacity: 1;
}
This is how it works now:

Vue adding dynamic class doesn't change current class

I have wrapper div with padding and I am dynamically adding items inside of it.
I don't want any padding on wrapper div when there is no item in it.
I have created computed method isEmpty to check if there are items or not and used it to add optional class :class={ className: isEmpty } but it doesn't work.
Here is the fiddle link: https://jsfiddle.net/2u9rtdmh/3/
You should wrap an expression for :class into ":
:class="{ className: isEmpty }"
You should read the console errors when trying to diagnose problems, i.e. your jsfiddle doesn't even have an #app element.
The correct syntax for your scenario would be :class="{ 'padding0' : isEmpty }"
Binding HTML Classes
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: "#app",
data: {
},
computed: {
isEmpty() {
return true;
}
}
})
body {
background-color: black;
}
.my-wrapper {
padding: 32px;
background-color: white;
}
.padding0 {
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div :class="{ 'padding0' : isEmpty }" class="my-wrapper">
<div>
<div>
</div>
</div>
</div>
</div>

Resources