JSFiddle - React, Tailwind, and code Playground

by ChangJoo Park

HTML

<div id="app">
  <div class="flex-container">
    <department-item v-for="list in listData" :key="list.name" :list-data="list"></department-item>
  </div>
</div>

<template id="department-item">
  <!-- box:start -->
  <div class="box">
    <div class="header">
      <div class="title">{{listData.name}}</div>
      <div class="action">&#x2b;</div>
    </div>
    <div class="body">
      <list-item-directory 
      v-for="directory in directories" 
        
      :key="directory.name" 
        
      :directory="directory"
      v-on:request-new-list="requestNewList"
      ></list-item-directory>
      <list-item-user v-for="user in users" :key="user.name" :user="user"></list-item-user>
    </div>
  </div>
  <!-- box:end -->
</template>

<template id="list-item-directory">
  <div class="item directory" v-on:click="requestNewList(directory)">
    <div class="avatar">
      &#128193;
    </div>
    <div class="profile-wrapper">
      <div class="name">{{directory.name}}</div>
      <div class="details">Users: {{directory.count}}</div>
    </div>
  </div>
</template>

<template id="list-item-user">
  <div class="item user">
    <img class="avatar" :src="user.profileImage">
    <div class="profile-wrapper">
      <div class="name">{{user.name}}</div>
      <div class="details">{{user.description}}</div>
    </div>
  </div>
</template>

<script src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/locales/ko/faker.ko.js"></script>

CSS

@import url('https://fonts.googleapis.com/css?family=Montserrat');
body {
  margin: 0;
  padding: 0;
  background-color: rgb(242, 242, 242);
  font-family: 'Montserrat', sans-serif;
}

.flex-container {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  flex-flow: row;
  height: 100%;
  position: absolute;
  width: 100%;
}

.box {
  background-color: #838c91;
  border: 1px solid white;
  flex: 1;
  -webkit-flex: 1;
  min-width: 300px;
  max-width: 300px;
  position: relative;
  display: flex;
  flex-direction: column;
  max-height: 100%;
  margin-right: 10px;
}

.header {
  background-color: #e2e4e6;
  padding: 10px;
  display: flex;
  position: relative;
  min-height: 20px;
  align-items: center;
}

.header .title {
  font-weight: bold;
  flex: 1;
}

.header .action {
  width: 10px;
  font-weight: bold;
  font-size: 20px;
  cursor: pointer;
}

.box .body {
  margin-top: 10px;
  min-height: 0;
  overflow: auto;
}

.box .body .item {
  margin: 5px;
  border-radius: 5px;
  margin-bottom: 5px;
  padding: 10px;
  color: DimGrey;
  background-color: #fff;
  display: flex;
  flex-direction: row;
  align-items: center;
  min-height: 40px;
  cursor: pointer;
  user-select: none;
}

.box .body .item:hover {
  background-color: #e2e4e6;
}

.user .avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 10px;
}

.directory .avatar {
  font-size: 25px;
  margin-right: 5px;
}

.profile-wrapper .name {
  font-size: 14px;
}

.profile-wrapper .details {
  font-size: 12px;
}

JavaScript

var res = []
var generateDepartment = function (requestName) {
	var newList = {
  	id: faker.random.uuid(),
  	type: 'list',
    name: requestName || faker.commerce.department(),
    data: {
    	directories: [],
      users: []
    }
  }
  var directoryCount = faker.random.number({min:2, max:5});
  for (var j = 0; j < directoryCount; j++) {
  	var newDirectory = {
    	id: faker.random.uuid(),
    	type: 'directory',
      name: faker.commerce.department(),
      count: faker.random.number(),
      listId: newList.id
		}
    newList.data.directories.push(newDirectory)
  }
  
  var userCount = faker.random.number({min:5, max:20});
  for (var k = 0; k < userCount; k++) {
  	var newUser = {
    	id: faker.random.uuid(),
    	type: 'user',
      name: faker.name.lastName() + faker.name.firstName(),
      description: faker.name.jobTitle(),
      profileImage: faker.image.avatar()
		}
		newList.data.users.push(newUser)
  }
  return newList
}

var moveList = function (requestDirectory) {
  return new Promise(function (resolve, rejct) {
    console.log('moveList : ',requestDirectory)
    var indexOfList = res.findIndex(function (list) {
    	return list.id === requestDirectory.listId
		})
    console.log(indexOfList)
    res.splice(indexOfList + 1, res.length - 1)
  	resolve()
  })
}

var listCount = 1;
for (var i = 0; i < listCount; i++) {
  res.push(generateDepartment())
}

var listItemUser = {
  name: 'list-item-user',
  template: '#list-item-user',
  props: ['user']
}

var listItemDirectory = {
  name: 'list-item-directory',
  template: '#list-item-directory',
  props: ['directory'],
  methods: {
    requestNewList: function(selectedDirectory) {
    	this.$emit('request-new-list', selectedDirectory)
    }
	}
}

var departmentItem = {
  name: 'department-item',
  template: '#department-item',
  props: ['listData'],
  created: function() {
    console.log(this.listData)
  },
  computed: {
  	directories: function () {
    	return this.listData.data.directories ||...