Simple changelog display with AngularJS and Flexbox
How do I make an simple changelog display with angularjs and flexbox?
Combining a few things I've learned about angular to make a (hopefully) usable and timesaving codebase for myself and fellow fontend devs : ). What is a simple changelog display with angularjs and flexbox? How do you make a simple changelog display with angularjs and flexbox? This script and codes were developed by Robert Lowe on 23 July 2022, Saturday.
Simple changelog display with AngularJS and Flexbox - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Simple changelog display with AngularJS and Flexbox</title> <link href='https://fonts.googleapis.com/css?family=Abel' rel='stylesheet' type='text/css'> <link rel='stylesheet prefetch' href='https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css'>
<link rel='stylesheet prefetch' href='https://cdn.jsdelivr.net/hint.css/1.3.5/hint.min.css'> <link rel="stylesheet" href="css/style.css">
</head>
<body>
<h2>Simple changelog display with AngularJS and Flexbox</h2>
<h3>Fully data driven with client-side sorting and paging</h3>
<div class="app-container" ng-app="angularPageApp"> <app-directive ng-controller="angularPageAppCtrl"></app-directive>
</div> <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.1/angular.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0-beta.0/angular-sanitize.min.js'></script> <script src="js/index.js"></script>
</body>
</html>
Simple changelog display with AngularJS and Flexbox - Script Codes CSS Codes
*, *::before, *::after { box-sizing: border-box;
}
body { font-family: 'Abel', sans-serif; margin: 0; padding: 0; background-color: #4FB477;
}
.flex { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: flex-star; align-items: stretch;
}
.flex-center { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: stretch;
}
.flex-column { display: flex; flex-direction: column; flex-wrap: wrap; justify-content: center; align-items: stretch;
}
.flex-column-center { display: flex; flex-direction: column; flex-wrap: wrap; justify-content: flex-start; align-items: center;
}
.flex-column-center-center { display: flex; flex-direction: column; flex-wrap: wrap; justify-content: center; align-items: center;
}
h2, h3 { color: #27593b; text-align: center;
}
h3 { font-size: 0.8em;
}
.content-container { font-size: 0.8em;
}
.content-container .content { margin: 1em;
}
.content-container .content .header { cursor: pointer; text-transform: uppercase; font-weight: bold; text-align: center;
}
.content-container .content .header .header.module-name { cursor: pointer; border-right: 0.2em solid #3E8E5E;
}
.content-container .content .header .header.module-name span { cursor: pointer;
}
.content-container .content .header .header.change-details,
.content-container .content .header .header.change-type { position: relative; text-align: center;
}
.content-container .content .header .header.change-details i,
.content-container .content .header .header.change-type i { position: absolute; top: 0.8em; left: 0.5em;
}
.content-container .content .header .header.change-details { background-color: #C2EABD; color: #173523; border-top-width: 0; border-bottom-width: 0; border-right: 0.2em solid #3E8E5E; cursor: pointer;
}
.content-container .content .header .header.change-type { position: relative; min-width: 6em; color: #173523; background-color: #C2EABD; border-top-right-radius: 0.2em; border-bottom-right-radius: 0.2em; line-height: 2.5em;
}
.content-container .content .item { margin: 0.5em; flex-wrap: nowrap;
}
.content-container .content .item:not(.header):hover .module-name { transform: scale(1.1);
}
.content-container .content .item:not(.header):hover .change-details { padding-left: 1.3em; padding-right: 1.3em;
}
.content-container .content .item:not(.header):hover .change-type { transform: scale(1.1); min-width: 6em; flex-flow: row nowrap; padding: 0 0.5em 0 0.5em;
}
.content-container .content .item:not(.header):hover .change-type span { transition: all 0.2s linear; position: relative; width: auto; visibility: visible; padding-left: 0.5em; margin-top: -0.1em;
}
.content-container .content .item .module-name,
.content-container .content .item .change-details { padding: 0.5em;
}
.content-container .content .item .module-name { display: flex; flex-direction: column; flex-wrap: wrap; justify-content: center; align-items: center; position: relative; min-width: 16em; background-color: #C2EABD; color: #173523; font-weight: bold; border-top-left-radius: 0.2em; border-bottom-left-radius: 0.2em; text-transform: uppercase; transition: transform 0.2s linear;
}
.content-container .content .item .module-name span { cursor: default;
}
.content-container .content .item .module-name i { position: absolute; top: 0.65em; left: 0.5em; font-size: 1.2em;
}
.content-container .content .item .module-name.small { font-size: 0.8em; padding-left: 3em; padding-right: 2.3em; min-width: 20em;
}
.content-container .content .item .module-name.small i { top: 1em; left: 0.65em;
}
.content-container .content .item .change-details { cursor: default; flex-grow: 1; background-color: #3E8E5E; color: #e6f6e4; border: 0.2em solid #C2EABD; border-right-width: 0; border-left-width: 0; transition: all 0.2s linear;
}
.content-container .content .item .change-type:not(.header) { min-width: 2.5em; ccolor: #173523; background-color: #C2EABD; border: 0.2em solid #C2EABD; border-left-width: 0; border-top-right-radius: 0.2em; border-bottom-right-radius: 0.2em; transition: transform 0.5s linear;
}
.content-container .content .item .change-type:not(.header) span { cursor: default; position: absolute; width: 0; visibility: hidden;
}
.client-side-pager-box { position: relative;
}
.client-side-pager-box .client-side-pager-size-select { position: absolute; top: 1.2em; left: 1.5em; height: 2em; background-color: #C2EABD;
}
.client-side-pager-box .client-side-pager-size-select:focus { outline: 0;
}
.client-side-pager-box .client-side-pager .client-side-page { background-color: #C2EABD; color: #173523; min-width: 2em; text-align: center; padding: 0.5em; margin: 0.5em; cursor: default;
}
.client-side-pager-box .client-side-pager .client-side-page:hover { transform: scale(1.2);
}
.client-side-pager-box .client-side-pager .client-side-page.active { background-color: #3E8E5E;
}
Simple changelog display with AngularJS and Flexbox - Script Codes JS Codes
var PageApp = angular.module('angularPageApp', ['ngSanitize']);
// simple filter for rendering html strings
PageApp.filter('renderHTMLCorrectly', function($sce)
{ return function(stringToParse) { return $sce.trustAsHtml(stringToParse); }
});
PageApp.controller('angularPageAppCtrl', function($scope) { // this is the array the client side pager will populate with changelog items $scope.pageRecords = []; // define your change types and their css classes // these should be defined alphabetically by name in order // for sorting by type to work properly $scope.types = { 1: { name: 'Addition', css: 'fa-plus' }, 2: { name: 'Bug Fix', css: 'fa-bug' }, 3: { name: 'New Feature', css: 'fa-star-o' }, 4: { name: 'Preview', css: 'fa-map-signs' }, }; // define change log headers and a sort state for each $scope.headers = { 1: { name: 'module', sort: 'none', css: 'module-name' }, 2: { name: 'details', sort: 'none', css: 'change-details' }, 3: { name: 'type', sort: 'none', css: 'change-type' } }; // define your modules and their css classes // these should be defined alphabetically by name in order // for sorting by module to work properly $scope.modules = { 1: { name: 'Company', icon: 'fa-group' }, 2: { name: 'Daily Field Billing Summary', icon: 'fa-road', small: true }, 3: { name: 'Dashboard', icon: 'fa-dashboard' }, 4: { name: 'Invoice Comments', icon: 'fa-commenting-o' }, 5: { name: 'Jobs', icon: 'fa-list' }, 6: { name: 'Labor Breakdown', icon: 'fa-truck' }, 7: { name: 'News Management', icon: 'fa-newspaper-o' }, 8: { name: 'Print Schedule', icon: 'fa-print' }, 9: { name: 'Scheduler', icon: 'fa-calendar-plus-o' }, 10: { name: 'Timelog', icon: 'fa-clock-o' } }; // define your change log item list. these could be fetched from a server // the client side pager directive will slice this list and set $scope.pageRecords according to the current page number and size $scope.items = [ { module: 1, details: 'Fixed an issue causing some states to not appear in the State selector', type: 2 }, { module: 2, details: 'Added Company Name column', type: 1 }, { module: 3, details: 'Widget selection is now based on Permissions rather than job title', type: 2 }, { module: 4, details: 'Fixed \'Written by\' field issue', type: 2 }, { module: 5, details: 'New Advanced Search feature', type: 3 }, { module: 5, details: 'Bug fixes related to Paging and Deleting records', type: 2 }, { module: 5, details: 'Now uses Section Township Block for West', type: 1 }, { module: 6, details: 'Added two new print formats, improved column sizing', type: 1 }, { module: 7, details: 'Patched issues with WYSIWYG editor', type: 2 }, { module: 8, details: 'Location name added to the report header', type: 1 }, { module: 9, details: 'New Special Add feature for cross-location scheduling', type: 3 }, { module: 9, details: 'Fixed an issue causing the last day of a month to appear blank', type: 2 }, { module: 10, details: '<b>* Coming Soon! *</b> New page consolidating all existing timelog pages into one', type: 4 } ]; // sorting method called when clicking a header $scope.sort = function(header) { var currentSort = header.sort; resetSort(); console.log('current sort: ', currentSort); header.sort = (currentSort === 'none' || currentSort === 'desc') ? 'asc' : 'desc'; switch(header.name) { case 'module': sortByModule(header); break; case 'details': sortByDetails(header); break; case 'type': sortByType(header); break; default: console.error('unknonw sort: ', header); } // notify the client side pager of the new item list $scope.$broadcast('update-pager', $scope.items); }; // enforce only one sort by value at any time var resetSort = function() { for(var index in $scope.headers) { var header = $scope.headers[index]; header.sort = 'none'; } }; // this will sort the items array by module id asc/desc var sortByModule = function(header) { $scope.items = (header.sort === 'asc') ? sortByKeyDesc($scope.items, 'module') : sortByKeyAsc($scope.items, 'module'); }; // this will sort the items array by details alphabetically asc/desc var sortByDetails = function(header) { $scope.items = (header.sort === 'asc') ? sortByKeyDesc($scope.items, 'details') : sortByKeyAsc($scope.items, 'details'); }; // this will sort the items array by type id asc/desc var sortByType = function(header) { $scope.items = (header.sort === 'asc') ? sortByKeyDesc($scope.items, 'type') : sortByKeyAsc($scope.items, 'type'); }; // simple sort by json key functions: // http://stackoverflow.com/questions/8175093/simple-function-to-sort-an-array-of-objects/8175221#8175221 function sortByKeyAsc(array, key) { return array.sort(function(a, b) { var x = a[key]; var y = b[key]; return ((x < y) ? -1 : ((x > y) ? 1 : 0)); }); } function sortByKeyDesc(array, key) { return array.sort(function(a, b) { var x = a[key]; var y = b[key]; return ((x < y) ? 1 : ((x > y) ? -1 : 0)); }); }
});
PageApp.directive('appDirective', function($timeout) { return { restrict: 'E', template: [ '<div class="content-container">', '<div class="content flex-column">', '<div class="header item flex">', '<div ng-repeat="header in headers" class="header {{ header.css }}" ng-click="sort(header)">', '<i class="fa" ng-class="{\'fa-sort-asc\': header.sort === \'asc\', \'fa-sort-desc\': header.sort === \'desc\', \'fa-sort\': header.sort === \'none\'}"></i>', '<span>{{ header.name }}</span>', '</div>', '</div>', '<div class="item flex" ng-repeat="item in pageRecords">', '<div class="module-name" ng-class="{small: modules[item.module].small}">', '<i class="module-icon fa {{ modules[item.module].icon }}"></i>', '<span>{{ modules[item.module].name }}</span>', '</div>', '<div class="change-details"><span ng-bind-html="item.details | renderHTMLCorrectly"></span></div>', '<div class="change-type flex-column-center-center">', '<i class="fa {{ types[item.type].css }}"></i>', '<span>{{ types[item.type].name }}</span>', '</div>', '</div>', '</div>', '</div>', '<client-side-pager size="6" options="6, 12, 24"></client-side-pager>' ].join(''), link: function(scope, element, attrs) { scope.$broadcast('update-pager', scope.items); } };
});
PageApp.controller('clientSidePagerCtrl', function($scope) { $scope.pageSize = null; // default page size list in case no 'options' attribute is provided $scope.pageSizeList = [5, 10, 20]; $scope.pageNumber = 1; $scope.recordList = []; $scope.getPageCount = function() { var pageCount = parseInt($scope.recordList.length / $scope.pageSize); if ( (pageCount * $scope.pageSize) < $scope.recordList.length ) { pageCount += 1; } return pageCount; }; $scope.getPageNumber = function() { return $scope.pageNumber; }; $scope.setPageNumber = function(page) { var newPageNumber = parseInt(page.text); if (newPageNumber === $scope.pageNumber) return; $scope.pageNumber = newPageNumber; $scope.update(); }; $scope.getPageList = function() { var pageCount = $scope.getPageCount(); var pageList = []; for(var i = 1; i <= pageCount; i++) { var pageItem = { text: i, active: false }; if (i === $scope.pageNumber) pageItem.active = true; pageList.push(pageItem); } return pageList; } $scope.getPageRecords = function() { var end = ($scope.pageSize * $scope.pageNumber), start = (end - $scope.pageSize); return $scope.recordList.slice(start, end); }; $scope.update = function() { $scope.$parent.pageRecords = $scope.getPageRecords(); $scope.pageList = $scope.getPageList(); }; $scope.parsePageSizeOptions = function(optionStr) { $scope.pageSizeList = optionStr.split(','); for(var i = 0; i < $scope.pageSizeList.length; i++) { $scope.pageSizeList[i] = parseInt($scope.pageSizeList[i]); } }; $scope.pageSizeChanged = function() { // if Page Size... was selected, just default to the first page size value if ($scope.pageSize === null) { $scope.pageSize = $scope.pageSizeList[0]; } $scope.pageNumber = 1; $scope.update(); }; $scope.$on('update-pager', function(event, recordList) { $scope.recordList = recordList; $scope.pageNumber = 1; $scope.update(); });
});
PageApp.directive('clientSidePager', function() { return { restrict: 'E', controller: 'clientSidePagerCtrl', template: [ '<div class="client-side-pager-box">', '<select class="client-side-pager-size-select" ng-show="pageList.length > 0" ng-model="pageSize" ng-options="item as item for item in pageSizeList" ng-change="pageSizeChanged()">', '<option value="">Page Size...</option>', '</select>', '<div class="client-side-pager flex-center">', '<div class="client-side-page" ng-class="{active: (pageNumber === page.text)}" ng-click="setPageNumber(page)" ng-repeat="page in pageList">{{ page.text }}</div>', '</div>', '</div>' ].join(''), scope: {}, link: function(scope, element, attrs) { scope.pageSize = parseInt(attrs.size); if (!attrs.options) return; scope.parsePageSizeOptions(attrs.options); } };
});
Developer | Robert Lowe |
Username | rlo206 |
Uploaded | July 23, 2022 |
Rating | 4 |
Size | 7,502 Kb |
Views | 34,408 |
Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!
Name | Size |
Crazy Tables | 3,065 Kb |
Draggables in pure angular | 5,167 Kb |
Dynamic UI with AngularJS attributes | 5,934 Kb |
Exploring ngForm | 7,554 Kb |
Learning to style range inputs | 4,175 Kb |
Customizable ripples with angular | 4,825 Kb |
Fly-Through-Loader | 2,936 Kb |
The Rainball | 4,656 Kb |
Editable Table Concept | 7,026 Kb |
CSS Color Wheel Loaders | 5,381 Kb |
Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!
Name | Username | Size |
Dice | Fraina | 5,026 Kb |
Simple Carousel Pure CSS | Dangvanthanh | 4,080 Kb |
Weather App | Kw7oe | 3,162 Kb |
Simple content swap | Snografx | 1,859 Kb |
Login-ng-modal | Heedoo | 3,566 Kb |
03 - CSS Variables | Run-time | 2,682 Kb |
Sticky menu on scroll | Senff | 2,869 Kb |
CSS Tooltips | Darylldoyle | 2,599 Kb |
Scroll to view if element partially out of view port height | ChrisMaki | 2,104 Kb |
SVG Hover Animations | Kjbrum | 10,557 Kb |
Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup. Hide Your IP Now!