- + +
+ +
+
+
Filter Google Summer of Code Projects
+
+
+ +
+ +
+
For more project ideas, click here.
@@ -21,6 +52,9 @@
+
+ {{ message.noProjectsFound }} +
{{ project.name }}
@@ -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 diff --git a/resources/css/style.css b/resources/css/style.css index cd39fd17..9aee65e0 100644 --- a/resources/css/style.css +++ b/resources/css/style.css @@ -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'; @@ -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; @@ -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; @@ -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; +} diff --git a/resources/js/app.js b/resources/js/app.js index 08620498..0a22c397 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -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(); }) } @@ -284,6 +476,7 @@ $scope.searchText = search_requested } + $scope.getAllFilters(); }, controllerAs: 'lc' }