Skip to content

Instantly share code, notes, and snippets.

@jackiewu
Created November 18, 2015 09:06
Show Gist options
  • Save jackiewu/e0017945cb9abf0de343 to your computer and use it in GitHub Desktop.
Save jackiewu/e0017945cb9abf0de343 to your computer and use it in GitHub Desktop.
User administration (responsive)
.page
.content
.header
.title
span.name Users
| (
span.count 0
|)
.functions
.add
.icon
i.fa.fa-plus
span Add user
.dataTable
table
thead
tr
th.selectAll
i.fa.fa-square-o
th Name
th Username
th E-mail
th Country
tbody
.properties
.slider
.propertyEditor
pjs = null
selectedObjs = undefined
# Change selection event
changeSelection = () ->
selectedRows = $(".dataTable table tbody tr.selected")
if selectedRows.length > 0
selectedObjs = ($(row).data("obj") for row in selectedRows)
refreshEditor()
# Refresh editor
refreshEditor = ->
pjs = new PJS ".propertyEditor", propertiesSchema, selectedObjs
dataSource = []
##################
# Generate users #
##################
generateFakeUsers = () ->
for i in [1..50]
user = faker.helpers.createCard()
user.bio = faker.lorem.sentence()
user.marked = faker.helpers.randomize([false, false, false, false, false, true])
user.status = faker.helpers.randomize([true, true, true, true, false])
user.password = user.username
dataSource.push user
#Create table row for item
initRow = (tr, item) ->
# Headerben lévő checkbox
selectAllCell = $(".dataTable table thead th.selectAll")
unless item.status
tr.addClass("inactive")
else
tr.removeClass("inactive")
if item.marked
tr.addClass("marked")
else
tr.removeClass("marked")
tr.empty().append [
$("<td/>").append $("<i/>").addClass("checkbox fa fa-square-o")
$("<td/>").text item.name || "<empty>"
$("<td/>").text item.username || "<empty>"
$("<td/>").text item.email || "<empty>"
$("<td/>").text item.address?.country || ""
]
tr.find("td:eq(0)").on "click", (e)->
e.preventDefault()
checkbox = tr.find("input[type=checkbox]")
state = tr.hasClass "selected"
if state
state = false
else
state = true
tr.toggleClass "selected"
selectAllCell.removeClass "selected"
changeSelection()
tr.find("td:not(:eq(0))").on "click", (e)->
tr.addClass("selected").siblings().removeClass("selected")
selectAllCell.removeClass "selected"
changeSelection()
refreshDataCount = ->
$(".header .count").text dataSource.length
##################
# Show datalist #
##################
$ ->
generateFakeUsers()
# console.log Faker
thead = $(".dataTable table thead")
tbody = $(".dataTable table tbody")
rows = []
selectAllCell = thead.find("th.selectAll")
$.each dataSource, (i, item) ->
tr = $("<tr/>").attr("data-id", i).data("obj", item)
initRow tr, item
item.__row = tr
rows.push tr
tbody.append rows
refreshDataCount()
selectAllCell.on "click", (e)->
if selectAllCell.hasClass "selected"
tbody.find("tr").removeClass "selected"
else
tbody.find("tr").addClass "selected"
selectAllCell.toggleClass "selected"
changeSelection()
# Set Add event handler
$(".header .functions .add").on "click", ->
selectedObjs = undefined
$(".dataTable tr.selected").removeClass("selected")
refreshEditor()
obj = pjs.getObject()
dataSource.push obj
selectedObjs = [obj]
refreshDataCount()
tr = $("<tr/>").data("obj", obj).addClass("selected")
initRow tr, obj
obj.__row = tr
tbody.append tr
$('.dataTable').stop().animate({
scrollTop: $('.dataTable table').height()
}, 500);
refreshEditor()
#################
# Handle slider #
#################
$doc = $(document)
dragging = false
ghost = null
$(".slider").on "mousedown", (e) ->
e.preventDefault()
dragging = true
width = $(".page").width()
offsetX = $(".page").offset().left
ghost = $("<div/>",
class: "ghostSlider"
css:
left: $(".properties").offset().left - offsetX
).appendTo $(".page")
$(".size").text(parseInt($(".properties").width()) + "px").fadeIn("fast")
$doc.on "mousemove", (ev) ->
dragging = true
ghost.css left: ev.pageX - offsetX
$(".size").text(parseInt(width - ev.pageX + offsetX) + "px")
$doc.on "mouseup", (ev) ->
e.preventDefault()
if dragging
$doc.off "mousemove mouseup"
$(".properties").css "flex": "0 0 " + (width - ghost.offset().left + offsetX) + "px"
ghost.remove();
dragging = false
# --- PROPERTIES SCHEMA ---
propertiesSchema = {
liveEdit: true
editors: [
field: "name"
title: "Name"
type: "text"
required: true
multiEdit: false
featured: true
,
field: "username"
title: "Username"
type: "text"
required: true
multiEdit: false
featured: true
,
field: "email"
title: "E-mail"
type: "email"
required: false
multiEdit: false
,
field: "password"
title: "Password"
type: "password"
placeHolder: "Password"
required: true
multiEdit: false
featured: true
toolTip: "Enter the user's password"
hint: "Minimum 6 characters"
validate: (value, objs) -> if value.length < 6 then return "Password is too short! Minimum 6 characters!"
,
field: "phone"
title: "Phone"
type: "text"
required: false
multiEdit: true
hint: "Format: 0-000-000-0000 x000"
,
field: "website"
title: "Website"
type: "text"
required: false
multiEdit: true
,
field: "address.country"
title: "Country"
type: "text"
required: false
multiEdit: true
,
field: "address.city"
title: "City"
type: "text"
required: false
multiEdit: true
,
field: "address.streetC"
title: "Street"
type: "text"
required: false
multiEdit: true
,
field: "address.zipcode"
title: "Zip"
type: "number"
required: false
multiEdit: true
,
field: "company.name"
title: "Company name"
type: "text"
required: false
multiEdit: true
,
field: "company.bs"
title: "Company keywords"
type: "text"
required: false
multiEdit: true
,
field: "bio"
title: "Biography"
type: "textarea"
required: false
multiEdit: true
rows: 3
,
field: "marked"
title: "Marked"
type: "boolean"
required: false
default: false
multiEdit: true
,
field: "status"
title: "Status"
type: "boolean"
required: true
default: true
multiEdit: true
,
field: "deleteUser"
title: "Delete user(s)"
type: "button"
schemaFunction: true
multiEdit: true
onclick: (objs)->
_.remove dataSource, (obj) ->
if objs.indexOf(obj) isnt -1
obj.__row.remove()
return true
refreshDataCount()
selectedObjs = []
refreshEditor()
],
onChanged: (editor, value, objs) ->
console.log "Field '#{editor.fieldName}' value changed to '#{value}'"
# showObjects()
$.each selectedObjs, (i, item) ->
initRow item.__row, item
}
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/102308/faker.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/102308/propertiesJS.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.7.0/lodash.min.js"></script>
@import "compass";
$backgroundColor: #E0E0E0;
$textColor: #012;
$selectedTextColor: #000;
$fontFamily: "Open Sans", "Helvetica Neue", Tahoma, sans-serif;
$fontFamilyAlt: "Open Sans Condensed", "Lato", "Segoe UI Light", Arial;
* {
@include box-sizing(border-box);
-webkit-font-smoothing: antialiased;
}
html {
color: $textColor;
font-size: 16px;
font-family: $fontFamily;
}
body {
background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/102308/Blur-4.jpg');
@include background-size(cover);
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
position: absolute;
left: 0;right: 0;
top: 0; bottom: 0;
padding: 0;
margin: 0;
}
@mixin clearfix() {
&:before,
&:after {
content: "";
display: table;
}
&:after {
clear: both;
}
}
$contentMargin: 4%;
.page {
position: absolute;
left: $contentMargin;
right: $contentMargin;
top: $contentMargin;
bottom: $contentMargin;
background-color: rgba(White, 0.4);
@include border-radius(10px);
@include box-shadow(0 0 10px rgba(Black, 0.8));
@include display-flex();
@include flex-direction(row);
overflow: hidden;
} // .page
%text-shadow {
@include text-shadow(0 0 2px rgba(Black, 0.4));
}
.content {
//background-color: rgba(Red, 0.2);
@include flex(1);
position: relative;
overflow: hidden;
@include display-flex();
@include flex-direction(column);
.header {
@include flex(0 0 36px);
padding: 8px 10px;
border-bottom: 1px solid rgba(White, 0.2);
background-color: rgba(White, 0.2);
.title {
float: left;
font-size: 0.8rem;
.name {
font-size: 1.3rem;
font-weight: bold;
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
}
.count {
}
} // .title
.functions {
float: right;
padding-right: 10px;
.add {
cursor: pointer;
opacity: 0.6;
@include transition(all .2s linear);
.icon {
display: inline-block;
border: 2px solid $textColor;
border-radius: 100%;
width: 25px;
height: 25px;
text-align: center;
padding: 1px 0 0 0;
font-size: 1.1rem;
@include transform(rotate(0deg));
@include transition(all .5s linear);
} // .icon
span {
overflow: hidden;
display: inline-block;
margin-left: 5px;
font-size: 0.8rem;
width: 0px;
font-weight: 600;
white-space: nowrap;
@include transition(all .2s ease);
} // span
&:hover {
span {
width: 60px;
}
opacity: 1.0;
.icon {
@include transform(rotate(180deg));
}
} // hover
} // .add
} // .functions
} // .header
.dataTable {
@include flex(1);
padding: 10px;
font-size: 0.9rem;
overflow: auto;
table {
width: 100%;
@include user-select(none);
thead {
tr {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
th {
text-align: left;
@extend %text-shadow;
font-weight: 700;
padding: 4px 2px;
vertical-align: middle;
text-transform: uppercase;
&.selectAll {
font-size: 1.1rem;
vertical-align: middle;
padding-right: 2px;
&.selected i:before {
content: "\f046";
}
}
} // th
} // tr
} // thead
tbody {
tr {
cursor: pointer;
@include text-shadow(0px 0px 3px rgba(0,0,0,0.2));
&:nth-child(even) {
background-color: rgba(Black, 0.05);
}
td {
padding: 8px 2px;
&:nth-child(1) .checkbox {
font-size: 1.1rem;
vertical-align: middle;
width: 18px;
}
} // td
&:hover {
background-color: rgba(Black, 0.1);
}
&.selected {
color: $selectedTextColor;
text-shadow: 0px 0px 3px rgba(0,0,0,0.8);
td:nth-child(1) .checkbox:before {
content: "\f046";
}
} // selected
&.inactive {
font-style: italic;
color: rgba($textColor, 0.5);
}
&.marked {
td:nth-child(2) {
&:after {
content: 'marked';
font-size: 0.6rem;
background-color: rgba(0, 92, 126, 0.17);
border: 1px solid rgba(0, 92, 126, 0.4);
color: White;
padding: 1px 3px;
@include border-radius(3px);
margin-left: 5px;
vertical-align: top;
}
}
}
} // tr
} // tbody
} // table
} // .dataTable
} // .content
.properties {
@include flex(0 0 23rem);
order: 1;
@include transition(all .25s ease);
position: relative;
@include display-flex();
@include flex-direction(row);
.slider {
@include flex(0 0 3px);
width: 3px;
height: 100vh;
background-color: rgba(Black, 0.1);
cursor: col-resize;
@include transition(background-color .3s linear);
&:hover {
background-color: rgba(Black, 0.5);
}
} // .slider
.propertyEditor {
@include flex(1);
overflow: auto;
background-color: transparent;
@include box-shadow(none);
@include border-radius(0px);
color: $textColor;
table {
thead {
background-color: rgba(White, 0.2);
border-bottom: 1px solid rgba(White, 0.3);
}
tr td {
@include text-shadow(0px 0px 3px rgba(0,0,0,0.2));
}
tr th {
padding: 8px 10px 9px 10px;
font-size: 1.1rem;
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
}
tr td:nth-child(2) {
.hint {
color: #6E6E6E;
}
input:not([type="checkbox"]), textarea, select, .checklist, .droplist {
background-color: rgba(White, 0.4);
color: $textColor;
@include text-shadow(1px 1px 2px rgba(0, 0, 0, 0.3));
}
button.function {
background-color: rgba(#444, 0.5);
&:hover {
background-color: rgba(#444, 0.7);
}
}
}
tr.validation-error .errors, tr.validation-error td:nth-child(1) {
color: #C70000;
}
}
}
} // .properties
@media (max-width: 1200px) {
.dataTable th:nth-child(5), .dataTable td:nth-child(5) {
display: none;
}
}
@media (max-width: 1000px) {
.dataTable th:nth-child(4), .dataTable td:nth-child(4) {
display: none;
}
}
@media (max-width: 900px) {
.dataTable th:nth-child(3), .dataTable td:nth-child(3) {
display: none;
}
}
@media (max-width: 700px) {
.page {
@include flex-direction(column);
}
.properties {
@include flex(0 0 31rem);
}
}
.ghostSlider {
position: absolute;
width: 3px;
height: 100vh;
background-color: rgba(Black, 0.5);
cursor: col-resize;
z-index: 9999;
} // .ghostSlider
::-webkit-scrollbar {
height: 8px;
width: 8px;
}
::-webkit-scrollbar-thumb {
background-color: rgba(Black, 0.4);
-webkit-border-radius: 1ex;
border: none;
}
::-webkit-scrollbar-corner {
background: rgba(Black, 0);
}
<link href="http://netdna.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.css" rel="stylesheet" />
<link href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/102308/propertiesJS.css" rel="stylesheet" />

User administration (responsive)

Responsive user administration UI (add, edit, delete, multi-select) with propertiesJS and Faker.js. You can resize the right sidebar too :)

A Pen by Icebob on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment