DUEL: Tag List

by nathanziarek

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/1.4.1/less.min.js"></script>
<script type="text/ng-template" id="MyWidget.html">
    <ul class="duel-taglist">
        <li ng-repeat="tag in taglist" class="is-{{tag.state}}">
            <div class="duel-taglist-tag" title="{{tag.message}}">{{tag.label}}
                <div class="duel-taglist-remove" title="Remove coupon {{tag.label}}"><i class="icon-remove"></i></div>
            </div>
            <!--<div class="ds-taglist-message">{{tag.message}}</div>-->
        </li>
    </ul>
</script>

<div ng-controller="CtrlA">
    <my-widget></my-widget>
</div>

CSS

@import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,600,700);

@basebackground: #e7e7e7;
@basepos: lighten(desaturate(green, 60%), 65%);
@baseneg: lighten(desaturate(red, 50%), 45%);
@tagHeight: 23px;

.duel-taglist {
    li { 
        height: @tagHeight+2;
        overflow: hidden;
        font-family: Open Sans;
        font-size: 12px;
        -width: 50%;
        margin-right: 10px;
        margin-bottom: 10px;
        float: left;
    }
    .duel-taglist-tag {
        height: @tagHeight;
        line-height: @tagHeight;
        border-radius: 10px;
        display: inline-block;
        padding: 0 30px 0 10px;
        position: relative;
        .duel-taglist-color(@basebackground);
        .duel-taglist-remove {
            position: absolute;
            right: 10px;
            top: 0;
            line-height: @tagHeight;
        }
    }
    .ds-taglist-message {
        display: inline-block;
        color: darken(@basebackground, 50%);
        margin-left: 5px;
        font-size: 11px;
    }
    .is-valid {
        .duel-taglist-tag {
            .duel-taglist-color(@basepos);
        }
    }
    .is-invalid {
        .duel-taglist-tag {
            .duel-taglist-color(@baseneg);
        }
    }

}

.duel-taglist-color(@backgroundcolor) {
    background: @backgroundcolor;
    border: 1px solid darken(@backgroundcolor, 15%);
    color: darken(@backgroundcolor, 65%);
    &:hover {
        background: darken(@backgroundcolor, 5%);
        border: 1px solid darken(@backgroundcolor, 20%);
        color: darken(@backgroundcolor, 70%);
        .duel-taglist-remove {
            color: darken(@backgroundcolor, 30%);
            &:hover {
                color: darken(@backgroundcolor, 60%);
            }
        }
    }
    .duel-taglist-remove {
        color: darken(@backgroundcolor, 15%);
    }
}

JavaScript

$('head style[type="text/css"]').attr('type', 'text/less'); less.refreshStyles();

var myApp = angular.module('myApp', []);

myApp.directive('myWidget', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: true,
        templateUrl: 'MyWidget.html',
        controller: 'MyWidget'
    }
});

function MyWidget($scope) {}

function CtrlA($scope) {
    $scope.taglist = [
        {
            "state": "unknown",
            "label": "FREESHIPPING"
        }, {
            "state": "valid",
            "label": "SAVE10PER"
        }, {
            "state": "invalid",
            "label": "ALL4FREE",
            "message": "Slightly longer message"
        }, {
            "state": "invalid",
            "label": "SUMMERSAVE",
            "message": "Coupon expired on 8.3.2013"
        }, {
            "state": "valid",
            "label": "BUYONEGETONE"
        }, {
            "state": "invalid",
            "label": "1MILNOFF",
            "message": "This code does not exist"
        }
    ];
}