Skip to content

Commit

Permalink
projects.html: Add filters for searching projects
Browse files Browse the repository at this point in the history
This commit adds filters for filtering the projects
based on project work status, tags, difficulty level,
initiatives and collaborating projects.

Closes coala#559
  • Loading branch information
KVGarg committed Aug 22, 2019
1 parent 4f4ef06 commit 8e239d6
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .coafile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ ignore =
_projects/README.md,
data/locale/en/projects/README.md,
# README.md symlinks: https://github.com/coala/coala-bears/issues/2950
max_lines_per_file = 500
max_lines_per_file = 1000

[filenames]
bears = FilenameBear
Expand Down
40 changes: 38 additions & 2 deletions partials/tabs/projects.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,39 @@
<br>
<div class="main-content container">
<div class="col m8 col offset-m2 s12">
<div class="input-field searchbar">
<input ng-model="searchText" placeholder="Search for a project" id="search" type="search" class="validate"> </div>
<div class="filter-projects-inputs">
<div class="input-field searchbar">
<input ng-model="searchText" placeholder="Search for a project" id="search" type="search" class="validate"> </div>
<div class="filter-btn apply-flex center-content">
<a id="filters" class="waves-effect waves-light btn-large" ng-click="toggleFiltersDisplay()">
<b>Filter Projects</b>
</a>
</div>
</div>
<div ng-class="{'display-none':!lc.displayFilters}" ng-click="toggleFiltersDisplay()">
<i class="fa fa-times close-filters"></i>
</div>
<div class="all-filters-option apply-flex center-content fade-in" ng-class="{'display-none':!lc.displayFilters}">
<h6><b>Filter Google Summer of Code Projects</b></h6>
<div class="filters-inputs apply-flex">
<div class="filter-select-fields apply-flex evenly-spread-content">
<label class="project-filter" ng-repeat="(filter, metadata) in projectFilterOptions">
<select class="{{ filter }}-selector" ng-model="metadata.model" ng-change="setModelList(filter, metadata.model)" name="{{ filter }}-selector" multiple>
<option value="" disabled>{{ metadata.label }}</option>
<option value="{{ value }}" ng-repeat="(key, value) in metadata.options">{{ key }}</option>
</select>
</label>
</div>
<div class="filter-btns">
<a class="waves-effect waves-light btn" ng-click="applyFilters()">
<i class="fa fa-check" aria-hidden="true"> Apply Filters</i>
</a>
<a class="waves-effect waves-light btn" ng-click="clearFilters()">
<i class="fa fa-trash-o clear-filters"> Clear Filters</i>
</a>
</div>
</div>
</div>
<div style="text-align: center;">
For more project ideas, <a href="https://github.com/coala/projects/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22Project+Proposal%22">click here</a>.
<br>
Expand All @@ -21,6 +52,9 @@
<div class="row outline">
<div class="parent-wrapper">
<div class="parent">
<div class="no-projects-found" ng-show="projectList.length === 0">
{{ message.noProjectsFound }}
</div>
<div ng-repeat="project in projectList | filter: searchText | orderBy: sortOrder" class="card child">
<div class="card-content waves-effect" ng-click="lc.showProject(project)">
<div class="card-title center">{{ project.name }}</div>
Expand Down Expand Up @@ -97,6 +131,8 @@
'slow');
})

$('.filter-select-fields select').material_select();

$('.modal').modal({
dismissible: true, // Modal can be dismissed by clicking outside of the modal
opacity: 0.8, // Opacity of modal background
Expand Down
79 changes: 76 additions & 3 deletions resources/css/style.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
.all-filters-option {
position: relative;
z-index: 1002;
min-width: 350px;
margin: 10px 0;
background-color: white;
box-shadow: 0 0 15px 2px black;
border-radius: 20px;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.apply-flex {
display: flex;
justify-content: center;
flex-flow: row wrap;
align-items: center;
}
.black-shadow {
box-shadow: 0 0 15px 2px black;
}
.center-align-text {
text-align: center;
.center-content {
justify-content: center;
}
.close-filters {
right: 6%;
margin-top: 1.25rem;
position: absolute;
z-index: 1003;
}
.display-none {
display: none;
}
.evenly-spread-content {
justify-content: space-evenly;
}
.hash_value_dup {
position: 'absolute';
Expand Down Expand Up @@ -42,6 +68,36 @@
.fa-clipboard:hover .hinttext {
visibility: visible;
}
.filter-projects-inputs {
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
margin-top: 1rem;
}
.filter-btn {
width: 165px;
z-index: 0;
}
.filter-btn .btn-large {
border-radius: 100px;
box-shadow: 0 0 10px 1px darkslategray;
}
.filters-btns {
width: 50%;
}
.filters-inputs {
justify-content: space-around;
padding: 20px 0;
}
.filter-select-fields {
width: 100%;
padding-top: 20px;
padding-bottom: 10px;
justify-content: space-around;
}
i.fa {
cursor: pointer;
}
.project-detail-element > .clickable:hover, .clickable:hover .chip:hover {
cursor: pointer;
background-color: #f3f5f8;
Expand Down Expand Up @@ -124,6 +180,11 @@
border: 0;
z-index: 9;
}
.searchbar {
width: 85%;
min-width: 340px;
margin-top: 0;
}
.sha256sum_hash {
display: flex;
justify-content: space-evenly;
Expand All @@ -136,3 +197,15 @@
#sha256sum_hash_value {
word-wrap: break-word;
}
@-webkit-keyframes fade-in {
0% {opacity: 0;}
100% {opacity: 1;}
}
@keyframes fade-in {
0% {opacity: 0;}
100% {opacity: 1;}
}
.fade-in {
-webkit-animation-name: fade-in;
animation-name: fade-in;
}
195 changes: 194 additions & 1 deletion resources/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,21 +97,213 @@
controller: function ($scope, $location, Languages) {
self = this

$scope.message = {}
$scope.projectFilterOptions = {}
$scope.selectedStatusesList = []
$scope.selectedTagsList = []
$scope.selectedLevelsList = []
$scope.selectedInitiativesList = []
$scope.selectedCollabsList = []

var mapping = {
'': 0,
'crowded': 1,
'in_progress': 2,
'completed': 3
'completed': 3,
'disabled': 4
}

self.displayFilters = false
$scope.toggleFiltersDisplay = function(){
self.displayFilters = !self.displayFilters
$('select').material_select();
}

$scope.sortOrder = function(project) {
return mapping[project.status];
}

$scope.getFiltersMetadata = function(){
$http.get('data/projects.liquid')
.then(function (res) {
var projects = res.data;
angular.forEach(projects, function(project){
if (project.status.length === 0){
$scope.projectFilterOptions.status.options['NOT YET STARTED'] = 0
}
angular.forEach(project.status, function(state){
$scope.projectFilterOptions.status.options[state.toUpperCase()] = mapping[state]
})
angular.forEach(project.tags, function(tag){
$scope.projectFilterOptions.tags.options[tag] = tag
})
$scope.projectFilterOptions.difficulty.options[project.difficulty.toUpperCase()] = project.difficulty
angular.forEach(project.initiatives, function(initiative){
$scope.projectFilterOptions.initiatives.options[initiative] = initiative
})
angular.forEach(project.collaborating_projects, function(collab){
$scope.projectFilterOptions['collab-projects'].options[collab] = collab
})
})
})
}

$scope.initializeSelectorData = function(name, label, model_name){
$scope.projectFilterOptions[name] = {
label: label, model: model_name,options: {}
}
}

$scope.getAllFilters = function () {
$scope.initializeSelectorData('status', 'Status', 'selectedStatusesList')
$scope.initializeSelectorData('tags', 'Project Tags', 'selectedTagsList')
$scope.initializeSelectorData('difficulty', 'Difficulty Level', 'selectedLevelsList')
$scope.initializeSelectorData('initiatives', 'Initiatives', 'selectedInitiativesList')
$scope.initializeSelectorData('collab-projects', 'Collaborating Projects', 'selectedCollabsList')
$scope.getFiltersMetadata()
}

function filterProjectsByStatus(projects){
var selectedProjects = []
angular.forEach(projects, function(project){
if (project.status.length === 0 && !selectedProjects.includes(project)){
if (
($scope.selectedStatusesList.includes("0") && project.mentors.length > 0) ||
($scope.selectedStatusesList.includes("4") && project.mentors.length === 0)
){
selectedProjects.push(project)
}
}
else {
angular.forEach(project.status, function (state) {
var mappedState = (mapping[state]).toString()
if ($scope.selectedStatusesList.includes(mappedState) && !selectedProjects.includes(project)) {
selectedProjects.push(project)
}
})
}
})
return selectedProjects
}

function filterProjectsByTags(projects){
var selectedProjects = []
angular.forEach(projects, function(project){
angular.forEach(project.tags, function(tag){
if ($scope.selectedTagsList.includes(tag) && !selectedProjects.includes(project)){
selectedProjects.push(project)
}
})
})
return selectedProjects
}

function filterProjectsByDifficulty(projects){
var selectedProjects = []
angular.forEach(projects, function(project){
if ($scope.selectedLevelsList.includes(project.difficulty) && !selectedProjects.includes(project)){
selectedProjects.push(project)
}
})
return selectedProjects
}

function filterProjectsByInitiatives(projects){
var selectedProjects = []
angular.forEach(projects, function(project){
angular.forEach(project.initiatives, function(initiative){
if ($scope.selectedInitiativesList.includes(initiative) && !selectedProjects.includes(project)){
selectedProjects.push(project)
}
})
})
return selectedProjects
}

function filterProjectsByCollaboratingProjects(projects){
var selectedProjects = []
angular.forEach(projects, function(project){
angular.forEach(project.collaborating_projects, function(collab){
if ($scope.selectedCollabsList.includes(collab) && !selectedProjects.includes(project)){
selectedProjects.push(project)
}
})
})
return selectedProjects
}

$scope.setModelList = function(filter, list){
if (filter === 'status'){
$scope.selectedStatusesList = list
}
else if (filter === 'tags'){
$scope.selectedTagsList = list
}
else if (filter === 'difficulty'){
$scope.selectedLevelsList = list
}
else if (filter === 'initiatives'){
$scope.selectedInitiativesList = list
}
else {
$scope.selectedCollabsList = list
}
}

function anyFiltersApplied(){
return (
$scope.selectedStatusesList.length > 0 ||
$scope.selectedTagsList.length > 0 ||
$scope.selectedLevelsList.length > 0 ||
$scope.selectedInitiativesList.length > 0 ||
$scope.selectedCollabsList.length > 0
)
}

$scope.applyFilters = function(){
var filteredProjects = $scope.allProjects
if(anyFiltersApplied()){
if ($scope.selectedStatusesList.length > 0 && filteredProjects.length > 0) {
filteredProjects = filterProjectsByStatus(filteredProjects)
}
if ($scope.selectedTagsList.length > 0 && filteredProjects.length > 0) {
filteredProjects = filterProjectsByTags(filteredProjects)
}
if ($scope.selectedLevelsList.length > 0 && filteredProjects.length > 0) {
filteredProjects = filterProjectsByDifficulty(filteredProjects)
}
if ($scope.selectedInitiativesList.length > 0 && filteredProjects.length > 0) {
filteredProjects = filterProjectsByInitiatives(filteredProjects)
}
if ($scope.selectedCollabsList.length > 0 && filteredProjects.length > 0) {
filteredProjects = filterProjectsByCollaboratingProjects(filteredProjects)
}
if (filteredProjects.length === 0){
$scope.message.noProjectsFound = 'No projects found for your selected filters' +
' options! Please try a different filter search combination.'
$scope.projectList = []
}
else {
$scope.projectList = filteredProjects
}
}
else {
$scope.projectList = filteredProjects
}
}

$scope.clearFilters = function(){
$scope.projectList = $scope.allProjects
var select = $('select')
select.prop('selectedIndex', 0)
select.material_select()
}

$scope.getDefaultProjectsMetadata = function () {
$http.get('data/projects.liquid')
.then(function (res) {
$scope.projectList = res.data;
$scope.allProjects = res.data;
$scope.projectRequest();
})
}
Expand Down Expand Up @@ -284,6 +476,7 @@
$scope.searchText = search_requested
}

$scope.getAllFilters();
},
controllerAs: 'lc'
}
Expand Down

0 comments on commit 8e239d6

Please sign in to comment.