Simple changelog display with AngularJS and Flexbox

Developer
Size
7,502 Kb
Views
34,408

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 Previews

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); } };
});
Simple changelog display with AngularJS and Flexbox - Script Codes
Simple changelog display with AngularJS and Flexbox - Script Codes
Home Page Home
Developer Robert Lowe
Username rlo206
Uploaded July 23, 2022
Rating 4
Size 7,502 Kb
Views 34,408
Do you need developer help for Simple changelog display with AngularJS and Flexbox?

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!

Robert Lowe (rlo206) Script Codes
Create amazing captions with AI!

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!