From 2ec1059b842ae42ae8d6e05a69049508661e0a50 Mon Sep 17 00:00:00 2001 From: koya0 Date: Mon, 23 Dec 2024 00:55:57 -0300 Subject: [PATCH 01/11] feat: add availability filter for issues --- .../fetch-and-display-previews.ts | 7 ++ .../sorting/filter-issues-by-availability.ts | 8 ++ src/home/sorting/sorting-manager.ts | 108 +++++++++++++++--- 3 files changed, 105 insertions(+), 18 deletions(-) create mode 100644 src/home/sorting/filter-issues-by-availability.ts diff --git a/src/home/fetch-github/fetch-and-display-previews.ts b/src/home/fetch-github/fetch-and-display-previews.ts index 5a4d10fd..41d2ae4a 100644 --- a/src/home/fetch-github/fetch-and-display-previews.ts +++ b/src/home/fetch-github/fetch-and-display-previews.ts @@ -4,6 +4,7 @@ import { applyAvatarsToIssues, renderGitHubIssues } from "../rendering/render-gi import { renderOrgHeaderLabel } from "../rendering/render-org-header"; import { closeModal } from "../rendering/render-preview-modal"; import { filterIssuesBySearch } from "../sorting/filter-issues-by-search"; +import { filterIssuesByAvailability } from "../sorting/filter-issues-by-availability"; import { Sorting } from "../sorting/generate-sorting-buttons"; import { sortIssuesController } from "../sorting/sort-issues-controller"; import { checkCacheIntegrityAndSyncTasks } from "./cache-integrity"; @@ -76,10 +77,12 @@ function filterIssuesByOrganization(issues: GitHubIssue[]): GitHubIssue[] { export async function displayGitHubIssues({ sorting, options = { ordering: "normal" }, + filterAvailableIssues = true, skipAnimation = false, }: { sorting?: Sorting; options?: { ordering: string }; + filterAvailableIssues?: boolean; skipAnimation?: boolean; } = {}) { await checkCacheIntegrityAndSyncTasks(); @@ -87,20 +90,24 @@ export async function displayGitHubIssues({ const sortedIssues = sortIssuesController(cachedTasks, sorting, options); let sortedAndFiltered = sortedIssues.filter(getProposalsOnlyFilter(isProposalOnlyViewer)); sortedAndFiltered = filterIssuesByOrganization(sortedAndFiltered); + sortedAndFiltered = filterAvailableIssues ? filterIssuesByAvailability(sortedAndFiltered) : sortedAndFiltered; renderGitHubIssues(sortedAndFiltered, skipAnimation); applyAvatarsToIssues(); } export async function searchDisplayGitHubIssues({ searchText, + filterAvailableIssues = true, skipAnimation = false, }: { searchText: string; + filterAvailableIssues?: boolean; skipAnimation?: boolean; }) { const searchResult = filterIssuesBySearch(searchText); let filteredIssues = searchResult.filter(getProposalsOnlyFilter(isProposalOnlyViewer)); filteredIssues = filterIssuesByOrganization(filteredIssues); + filteredIssues = filterAvailableIssues ? filterIssuesByAvailability(filteredIssues) : filteredIssues; renderGitHubIssues(filteredIssues, skipAnimation); applyAvatarsToIssues(); } diff --git a/src/home/sorting/filter-issues-by-availability.ts b/src/home/sorting/filter-issues-by-availability.ts new file mode 100644 index 00000000..050bd3ff --- /dev/null +++ b/src/home/sorting/filter-issues-by-availability.ts @@ -0,0 +1,8 @@ +import { GitHubIssue } from "../github-types"; + +export function filterIssuesByAvailability(issues: GitHubIssue[]) { + return issues.filter((issue) => { + if (issue.assignee) return false; + return true; + }); +} diff --git a/src/home/sorting/sorting-manager.ts b/src/home/sorting/sorting-manager.ts index 58da05fa..e81241bc 100644 --- a/src/home/sorting/sorting-manager.ts +++ b/src/home/sorting/sorting-manager.ts @@ -8,7 +8,9 @@ export class SortingManager { private _toolBarFilters: HTMLElement; private _filterTextBox: HTMLInputElement; private _sortingButtons: HTMLElement; + private _filterAvailableIssuesButton: HTMLElement; private _instanceId: string; + private _filterAvailableIssues: boolean = true; private _sortingState: { [key: string]: "unsorted" | "ascending" | "descending" } = {}; // Track state for each sorting option constructor(filtersId: string, sortingOptions: readonly string[], instanceId: string) { @@ -20,6 +22,8 @@ export class SortingManager { // Initialize sorting buttons first this._sortingButtons = this._generateSortingButtons(sortingOptions); + // Initialize filter available issues button + this._filterAvailableIssuesButton = this._generateFilterAvailableIssuesButton(); // Then initialize filter text box this._filterTextBox = this._generateFilterTextBox(); @@ -32,6 +36,7 @@ export class SortingManager { public render() { this._toolBarFilters.appendChild(this._filterTextBox); this._toolBarFilters.appendChild(this._sortingButtons); + this._toolBarFilters.appendChild(this._filterAvailableIssuesButton); } private _generateFilterTextBox() { @@ -66,6 +71,7 @@ export class SortingManager { try { void searchDisplayGitHubIssues({ searchText: searchQuery, + filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorInModal(error as Error); @@ -93,6 +99,7 @@ export class SortingManager { try { void searchDisplayGitHubIssues({ searchText: filterText, + filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorInModal(error as Error); @@ -105,6 +112,7 @@ export class SortingManager { try { void searchDisplayGitHubIssues({ searchText: textBox.value, + filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorInModal(error as Error); @@ -115,10 +123,18 @@ export class SortingManager { return textBox; } + private _resetSearchBar() { + this._filterTextBox.value = ""; + const newURL = new URL(window.location.href); + newURL.searchParams.delete("search"); + window.history.replaceState({}, "", newURL.toString()); + } + private _resetSortButtons() { this._sortingButtons.querySelectorAll('input[type="radio"]').forEach((input) => { if (input instanceof HTMLInputElement) { input.checked = false; + this._sortingState[input.value] = "unsorted"; input.setAttribute("data-ordering", ""); } }); @@ -148,6 +164,65 @@ export class SortingManager { return buttons; } + private _generateFilterAvailableIssuesButton() { + const div = document.createElement("div"); + div.className = "labels"; + + const input = document.createElement("input"); + input.type = "button"; + input.value = "filter availability"; + input.id = `filter-availability-${this._instanceId}`; + + const label = document.createElement("label"); + label.htmlFor = `filter-availability-${this._instanceId}`; + label.textContent = "Show All Issues"; + + input.addEventListener("click", () => { + this._filterAvailableIssues = !this._filterAvailableIssues; + label.textContent = this._filterAvailableIssues ? "Show All Issues" : "Show Available Issues"; + + try { + // Clear search when applying the filter + this._resetSearchBar(); + + const { sortingOption, sortingOrder } = this._detectSortingState(); + void displayGitHubIssues({ + sorting: sortingOption as Sorting, + options: { ordering: sortingOrder }, + filterAvailableIssues: this._filterAvailableIssues, + }); + } catch (error) { + renderErrorInModal(error as Error); + } + }); + + div.appendChild(input); + div.appendChild(label); + + return div; + } + + private _detectSortingState() { + let sortingOption; + let sortingOrder = "normal"; + + for (const option of Object.keys(this._sortingState)) { + const order = this._sortingState[option]; + + if (order !== "unsorted") { + sortingOption = option; + + if (order === "descending") { + sortingOrder = "normal"; + } else if (order === "ascending") { + sortingOrder = "reverse"; + } + break; + } + } + return { sortingOption, sortingOrder }; + } + private _createRadioButton(option: string): HTMLInputElement { const input = document.createElement("input"); input.type = "radio"; @@ -168,35 +243,26 @@ export class SortingManager { const currentOrdering = input.getAttribute("data-ordering"); let newOrdering: string; + // Reset sort buttons + this._resetSortButtons(); + // Determine the new ordering based on the current state if (currentOrdering === "normal") { newOrdering = "reverse"; + this._sortingState[option] = "ascending"; } else if (currentOrdering === "reverse") { newOrdering = "disabled"; + this._sortingState[option] = "unsorted"; } else { newOrdering = "normal"; + this._sortingState[option] = "descending"; } // Apply the new ordering state input.setAttribute("data-ordering", newOrdering); - input.parentElement?.childNodes.forEach((node) => { - if (node instanceof HTMLInputElement) { - node.setAttribute("data-ordering", ""); - } - }); // Clear search when applying a different sort - this._filterTextBox.value = ""; - const newURL = new URL(window.location.href); - newURL.searchParams.delete("search"); - window.history.replaceState({}, "", newURL.toString()); - - // Reset other buttons - input.parentElement?.childNodes.forEach((node) => { - if (node instanceof HTMLInputElement) { - node.setAttribute("data-ordering", ""); - } - }); + this._resetSearchBar(); if (newOrdering === "disabled") { this._lastChecked = null; @@ -209,7 +275,11 @@ export class SortingManager { // Apply the sorting based on the new state (normal or reverse) try { - void displayGitHubIssues({ sorting: option as Sorting, options: { ordering: newOrdering } }); + void displayGitHubIssues({ + sorting: option as Sorting, + options: { ordering: newOrdering }, + filterAvailableIssues: this._filterAvailableIssues, + }); } catch (error) { renderErrorCatch(error as ErrorEvent); } @@ -218,7 +288,9 @@ export class SortingManager { private _clearSorting() { try { - void displayGitHubIssues(); + void displayGitHubIssues({ + filterAvailableIssues: this._filterAvailableIssues, + }); } catch (error) { renderErrorInModal(error as Error); } From 84a0ef378f76c4aa0e04dc76ec5044b6e6b702bd Mon Sep 17 00:00:00 2001 From: koya0 Date: Mon, 23 Dec 2024 00:58:03 -0300 Subject: [PATCH 02/11] style: change width of buttons for auto and add min-width of 55px --- static/style/inverted-style.css | 5 +++-- static/style/style.css | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index f1f7836e..f1103f3c 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -247,7 +247,8 @@ text-align: center; white-space: nowrap; background-color: #7f7f7f20; - width: 64px; + min-width: 55px; + width: auto; letter-spacing: 0.5px; flex-grow: 4; justify-content: center; @@ -258,7 +259,7 @@ overflow: hidden; display: inline-block; } - input[type="radio"] { + input[type="radio"], input[type="button"] { background-color: unset; cursor: default; appearance: unset; diff --git a/static/style/style.css b/static/style/style.css index 7080a8d0..d402758f 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -247,7 +247,8 @@ text-align: center; white-space: nowrap; background-color: #80808020; - width: 64px; + min-width: 55px; + width: auto; letter-spacing: 0.5px; flex-grow: 4; justify-content: center; @@ -258,7 +259,7 @@ overflow: hidden; display: inline-block; } - input[type="radio"] { + input[type="radio"], input[type="button"] { background-color: unset; cursor: default; appearance: unset; From a2f32aa7a55ef4bfd1f45bae276efc757cbc5c3d Mon Sep 17 00:00:00 2001 From: koya0 Date: Thu, 26 Dec 2024 18:28:35 -0300 Subject: [PATCH 03/11] refactor: reorganize filter elements and update styles for filter button and search bar --- src/home/sorting/sorting-manager.ts | 41 +++++++++++++---------------- static/style/inverted-style.css | 38 +++++++++++++++++++------- static/style/style.css | 38 +++++++++++++++++++------- 3 files changed, 75 insertions(+), 42 deletions(-) diff --git a/src/home/sorting/sorting-manager.ts b/src/home/sorting/sorting-manager.ts index e81241bc..94ffab39 100644 --- a/src/home/sorting/sorting-manager.ts +++ b/src/home/sorting/sorting-manager.ts @@ -6,9 +6,8 @@ import { Sorting } from "./generate-sorting-buttons"; export class SortingManager { private _lastChecked: HTMLInputElement | null = null; private _toolBarFilters: HTMLElement; - private _filterTextBox: HTMLInputElement; + private _filtersDiv: HTMLElement; private _sortingButtons: HTMLElement; - private _filterAvailableIssuesButton: HTMLElement; private _instanceId: string; private _filterAvailableIssues: boolean = true; private _sortingState: { [key: string]: "unsorted" | "ascending" | "descending" } = {}; // Track state for each sorting option @@ -22,10 +21,12 @@ export class SortingManager { // Initialize sorting buttons first this._sortingButtons = this._generateSortingButtons(sortingOptions); - // Initialize filter available issues button - this._filterAvailableIssuesButton = this._generateFilterAvailableIssuesButton(); - // Then initialize filter text box - this._filterTextBox = this._generateFilterTextBox(); + // Initialize filters div + this._filtersDiv = this._generateFiltersDiv(); + // Add filter search box to filters div + this._filtersDiv.appendChild(this._generateFilterTextBox()); + // Add filter available issues button to filters div + this._filtersDiv.appendChild(this._generateFilterAvailableIssuesButton()); // Initialize sorting states to 'unsorted' for all options sortingOptions.forEach((option) => { @@ -34,9 +35,14 @@ export class SortingManager { } public render() { - this._toolBarFilters.appendChild(this._filterTextBox); + this._toolBarFilters.appendChild(this._filtersDiv); this._toolBarFilters.appendChild(this._sortingButtons); - this._toolBarFilters.appendChild(this._filterAvailableIssuesButton); + } + + private _generateFiltersDiv() { + const div = document.createElement("div"); + div.className = "filters"; + return div; } private _generateFilterTextBox() { @@ -124,7 +130,8 @@ export class SortingManager { } private _resetSearchBar() { - this._filterTextBox.value = ""; + const filterTextBox = this._filtersDiv.querySelector('input[type="text"]') as HTMLInputElement; + filterTextBox.value = ""; const newURL = new URL(window.location.href); newURL.searchParams.delete("search"); window.history.replaceState({}, "", newURL.toString()); @@ -165,21 +172,14 @@ export class SortingManager { } private _generateFilterAvailableIssuesButton() { - const div = document.createElement("div"); - div.className = "labels"; - const input = document.createElement("input"); input.type = "button"; - input.value = "filter availability"; + input.value = "All Issues"; input.id = `filter-availability-${this._instanceId}`; - const label = document.createElement("label"); - label.htmlFor = `filter-availability-${this._instanceId}`; - label.textContent = "Show All Issues"; - input.addEventListener("click", () => { this._filterAvailableIssues = !this._filterAvailableIssues; - label.textContent = this._filterAvailableIssues ? "Show All Issues" : "Show Available Issues"; + input.value = this._filterAvailableIssues ? "All Issues" : "Unassigned Issues"; try { // Clear search when applying the filter @@ -196,10 +196,7 @@ export class SortingManager { } }); - div.appendChild(input); - div.appendChild(label); - - return div; + return input; } private _detectSortingState() { diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index f1103f3c..8f917b9f 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -1,4 +1,4 @@ -@media (orientation: portrait) or (max-width: 1005px) { +@media (orientation: portrait) or (max-width: 1050px) { #filters { display: none; } @@ -247,8 +247,7 @@ text-align: center; white-space: nowrap; background-color: #7f7f7f20; - min-width: 55px; - width: auto; + width: 64px; letter-spacing: 0.5px; flex-grow: 4; justify-content: center; @@ -259,7 +258,7 @@ overflow: hidden; display: inline-block; } - input[type="radio"], input[type="button"] { + input[type="radio"] { background-color: unset; cursor: default; appearance: unset; @@ -682,24 +681,43 @@ /* width: 100%; */ /* justify-content: normal; */ } - .filters-container input[type="text"] { + .filters { + display: flex; + min-width: 50%; + } + .filters input[type="text"] { padding: 4px; border: none; border-radius: 4px; background-color: #7f7f7f20; height: 16px; text-align: center; + width: 75%; } - #filter-top { - width: calc(100vw / 3); - } - .filters-container input[type="text"]::placeholder { + .filters input[type="text"]::placeholder { font-size: 12px; letter-spacing: 0.5px; } - .filters-container input[type="text"].hidden { + .filters input[type="text"].hidden { display: none; } + .filters input[type="button"] { + padding: 4px; + border: none; + border-radius: 4px; + margin: 0 4px 0 4px; + font-size: 12px; + text-align: center; + background-color: #7f7f7f20; + letter-spacing: 0.5px; + text-overflow: ellipsis; + overflow: hidden; + cursor: pointer; + width: 25%; + } + .filters input[type="button"]:hover { + background-color: #7f7f7f40; + } button#github-login-button { margin-left: auto; } diff --git a/static/style/style.css b/static/style/style.css index d402758f..b18fd143 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -1,4 +1,4 @@ -@media (orientation: portrait) or (max-width: 1005px) { +@media (orientation: portrait) or (max-width: 1050px) { #filters { display: none; } @@ -247,8 +247,7 @@ text-align: center; white-space: nowrap; background-color: #80808020; - min-width: 55px; - width: auto; + width: 64px; letter-spacing: 0.5px; flex-grow: 4; justify-content: center; @@ -259,7 +258,7 @@ overflow: hidden; display: inline-block; } - input[type="radio"], input[type="button"] { + input[type="radio"] { background-color: unset; cursor: default; appearance: unset; @@ -682,24 +681,43 @@ /* width: 100%; */ /* justify-content: normal; */ } - .filters-container input[type="text"] { + .filters { + display: flex; + min-width: 50%; + } + .filters input[type="text"] { padding: 4px; border: none; border-radius: 4px; background-color: #80808020; height: 16px; text-align: center; + width: 75%; } - #filter-top { - width: calc(100vw / 3); - } - .filters-container input[type="text"]::placeholder { + .filters input[type="text"]::placeholder { font-size: 12px; letter-spacing: 0.5px; } - .filters-container input[type="text"].hidden { + .filters input[type="text"].hidden { display: none; } + .filters input[type="button"] { + padding: 4px; + border: none; + border-radius: 4px; + margin: 0 4px 0 4px; + font-size: 12px; + text-align: center; + background-color: #80808020; + letter-spacing: 0.5px; + text-overflow: ellipsis; + overflow: hidden; + cursor: pointer; + width: 25%; + } + .filters input[type="button"]:hover { + background-color: #80808040; + } button#github-login-button { margin-left: auto; } From cef819b84b1facc165283dc5473e2d2b450435bf Mon Sep 17 00:00:00 2001 From: koya0 Date: Thu, 26 Dec 2024 19:45:04 -0300 Subject: [PATCH 04/11] style: update filter button styles and adjust layout for better responsiveness --- src/home/sorting/sorting-manager.ts | 2 +- static/style/inverted-style.css | 9 +++++++-- static/style/style.css | 9 +++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/home/sorting/sorting-manager.ts b/src/home/sorting/sorting-manager.ts index 94ffab39..b7d772b3 100644 --- a/src/home/sorting/sorting-manager.ts +++ b/src/home/sorting/sorting-manager.ts @@ -179,7 +179,7 @@ export class SortingManager { input.addEventListener("click", () => { this._filterAvailableIssues = !this._filterAvailableIssues; - input.value = this._filterAvailableIssues ? "All Issues" : "Unassigned Issues"; + input.value = this._filterAvailableIssues ? "All Issues" : "Unassigned"; try { // Clear search when applying the filter diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index 8f917b9f..fcf7ac55 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -5,6 +5,9 @@ .filters-container label:not([for="view-toggle"]) { width: 48px; } + .filters { + width: 100%; + } #bottom-right { display: none; } @@ -684,6 +687,7 @@ .filters { display: flex; min-width: 50%; + margin-left: 2px; } .filters input[type="text"] { padding: 4px; @@ -702,10 +706,11 @@ display: none; } .filters input[type="button"] { - padding: 4px; + padding: 4px 6px; border: none; + margin-left: 4px; + margin-right: 4px; border-radius: 4px; - margin: 0 4px 0 4px; font-size: 12px; text-align: center; background-color: #7f7f7f20; diff --git a/static/style/style.css b/static/style/style.css index b18fd143..ff56491b 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -5,6 +5,9 @@ .filters-container label:not([for="view-toggle"]) { width: 48px; } + .filters { + width: 100%; + } #bottom-right { display: none; } @@ -684,6 +687,7 @@ .filters { display: flex; min-width: 50%; + margin-left: 2px; } .filters input[type="text"] { padding: 4px; @@ -702,10 +706,11 @@ display: none; } .filters input[type="button"] { - padding: 4px; + padding: 4px 6px; border: none; + margin-left: 4px; + margin-right: 4px; border-radius: 4px; - margin: 0 4px 0 4px; font-size: 12px; text-align: center; background-color: #80808020; From 1c742295933813cad984357233552d51ab3d580c Mon Sep 17 00:00:00 2001 From: koya0 Date: Thu, 26 Dec 2024 20:19:46 -0300 Subject: [PATCH 05/11] feat: swap availability filter button text --- src/home/sorting/sorting-manager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/home/sorting/sorting-manager.ts b/src/home/sorting/sorting-manager.ts index b7d772b3..774e8f34 100644 --- a/src/home/sorting/sorting-manager.ts +++ b/src/home/sorting/sorting-manager.ts @@ -174,12 +174,12 @@ export class SortingManager { private _generateFilterAvailableIssuesButton() { const input = document.createElement("input"); input.type = "button"; - input.value = "All Issues"; + input.value = "Unassigned"; input.id = `filter-availability-${this._instanceId}`; input.addEventListener("click", () => { this._filterAvailableIssues = !this._filterAvailableIssues; - input.value = this._filterAvailableIssues ? "All Issues" : "Unassigned"; + input.value = this._filterAvailableIssues ? "Unassigned" : "All Issues"; try { // Clear search when applying the filter From f2f99fa12211c8649ce92393981bd20a0bf1b6eb Mon Sep 17 00:00:00 2001 From: koya0 Date: Thu, 26 Dec 2024 20:58:42 -0300 Subject: [PATCH 06/11] feat: remove filterAvailableIssues parameter from displayGithubIssues --- .../fetch-and-display-previews.ts | 22 ++++++++----------- src/home/sorting/sorting-manager.ts | 15 ++++--------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/home/fetch-github/fetch-and-display-previews.ts b/src/home/fetch-github/fetch-and-display-previews.ts index 41d2ae4a..e6edbc8b 100644 --- a/src/home/fetch-github/fetch-and-display-previews.ts +++ b/src/home/fetch-github/fetch-and-display-previews.ts @@ -13,6 +13,12 @@ export type Options = { ordering: "normal" | "reverse"; }; +export let isFilteringAvailableIssues = true; + +export function swapAvailabilityFilter() { + isFilteringAvailableIssues = !isFilteringAvailableIssues; +} + // start at view based on URL export let isProposalOnlyViewer = new URLSearchParams(window.location.search).get("proposal") === "true"; @@ -77,12 +83,10 @@ function filterIssuesByOrganization(issues: GitHubIssue[]): GitHubIssue[] { export async function displayGitHubIssues({ sorting, options = { ordering: "normal" }, - filterAvailableIssues = true, skipAnimation = false, }: { sorting?: Sorting; options?: { ordering: string }; - filterAvailableIssues?: boolean; skipAnimation?: boolean; } = {}) { await checkCacheIntegrityAndSyncTasks(); @@ -90,24 +94,16 @@ export async function displayGitHubIssues({ const sortedIssues = sortIssuesController(cachedTasks, sorting, options); let sortedAndFiltered = sortedIssues.filter(getProposalsOnlyFilter(isProposalOnlyViewer)); sortedAndFiltered = filterIssuesByOrganization(sortedAndFiltered); - sortedAndFiltered = filterAvailableIssues ? filterIssuesByAvailability(sortedAndFiltered) : sortedAndFiltered; + sortedAndFiltered = isFilteringAvailableIssues ? filterIssuesByAvailability(sortedAndFiltered) : sortedAndFiltered; renderGitHubIssues(sortedAndFiltered, skipAnimation); applyAvatarsToIssues(); } -export async function searchDisplayGitHubIssues({ - searchText, - filterAvailableIssues = true, - skipAnimation = false, -}: { - searchText: string; - filterAvailableIssues?: boolean; - skipAnimation?: boolean; -}) { +export async function searchDisplayGitHubIssues({ searchText, skipAnimation = false }: { searchText: string; skipAnimation?: boolean }) { const searchResult = filterIssuesBySearch(searchText); let filteredIssues = searchResult.filter(getProposalsOnlyFilter(isProposalOnlyViewer)); filteredIssues = filterIssuesByOrganization(filteredIssues); - filteredIssues = filterAvailableIssues ? filterIssuesByAvailability(filteredIssues) : filteredIssues; + filteredIssues = isFilteringAvailableIssues ? filterIssuesByAvailability(filteredIssues) : filteredIssues; renderGitHubIssues(filteredIssues, skipAnimation); applyAvatarsToIssues(); } diff --git a/src/home/sorting/sorting-manager.ts b/src/home/sorting/sorting-manager.ts index 774e8f34..cbe7ee09 100644 --- a/src/home/sorting/sorting-manager.ts +++ b/src/home/sorting/sorting-manager.ts @@ -2,6 +2,7 @@ import { displayGitHubIssues, searchDisplayGitHubIssues } from "../fetch-github/ import { renderErrorInModal } from "../rendering/display-popup-modal"; import { proposalViewToggle } from "../rendering/render-github-issues"; import { Sorting } from "./generate-sorting-buttons"; +import { isFilteringAvailableIssues, swapAvailabilityFilter } from "../fetch-github/fetch-and-display-previews"; export class SortingManager { private _lastChecked: HTMLInputElement | null = null; @@ -9,7 +10,6 @@ export class SortingManager { private _filtersDiv: HTMLElement; private _sortingButtons: HTMLElement; private _instanceId: string; - private _filterAvailableIssues: boolean = true; private _sortingState: { [key: string]: "unsorted" | "ascending" | "descending" } = {}; // Track state for each sorting option constructor(filtersId: string, sortingOptions: readonly string[], instanceId: string) { @@ -77,7 +77,6 @@ export class SortingManager { try { void searchDisplayGitHubIssues({ searchText: searchQuery, - filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorInModal(error as Error); @@ -105,7 +104,6 @@ export class SortingManager { try { void searchDisplayGitHubIssues({ searchText: filterText, - filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorInModal(error as Error); @@ -118,7 +116,6 @@ export class SortingManager { try { void searchDisplayGitHubIssues({ searchText: textBox.value, - filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorInModal(error as Error); @@ -178,8 +175,8 @@ export class SortingManager { input.id = `filter-availability-${this._instanceId}`; input.addEventListener("click", () => { - this._filterAvailableIssues = !this._filterAvailableIssues; - input.value = this._filterAvailableIssues ? "Unassigned" : "All Issues"; + swapAvailabilityFilter(); + input.value = isFilteringAvailableIssues ? "Unassigned" : "All Issues"; try { // Clear search when applying the filter @@ -189,7 +186,6 @@ export class SortingManager { void displayGitHubIssues({ sorting: sortingOption as Sorting, options: { ordering: sortingOrder }, - filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorInModal(error as Error); @@ -275,7 +271,6 @@ export class SortingManager { void displayGitHubIssues({ sorting: option as Sorting, options: { ordering: newOrdering }, - filterAvailableIssues: this._filterAvailableIssues, }); } catch (error) { renderErrorCatch(error as ErrorEvent); @@ -285,9 +280,7 @@ export class SortingManager { private _clearSorting() { try { - void displayGitHubIssues({ - filterAvailableIssues: this._filterAvailableIssues, - }); + void displayGitHubIssues(); } catch (error) { renderErrorInModal(error as Error); } From 04709276977610922b7d1d4d424794f0672905d3 Mon Sep 17 00:00:00 2001 From: koya0 Date: Thu, 26 Dec 2024 20:59:07 -0300 Subject: [PATCH 07/11] style: update media query breakpoint for landscape orientation --- static/style/inverted-style.css | 2 +- static/style/style.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index fcf7ac55..1a85346f 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -46,7 +46,7 @@ margin: 0; } } -@media (orientation: landscape) and (width > 800px) { +@media (orientation: landscape) and (width > 1050px) { #bottom-bar, #filters-bottom { display: none; diff --git a/static/style/style.css b/static/style/style.css index ff56491b..0c969ce9 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -46,7 +46,7 @@ margin: 0; } } -@media (orientation: landscape) and (width > 800px) { +@media (orientation: landscape) and (width > 1050px) { #bottom-bar, #filters-bottom { display: none; From d3862b21050c9cb24aba75134031e45164e18253 Mon Sep 17 00:00:00 2001 From: koya0 Date: Sat, 4 Jan 2025 01:14:11 -0300 Subject: [PATCH 08/11] fix: adjust min-width of toggle button --- static/style/inverted-style.css | 3 ++- static/style/style.css | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index 1a85346f..0f2a069a 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -688,6 +688,7 @@ display: flex; min-width: 50%; margin-left: 2px; + gap: 4px; } .filters input[type="text"] { padding: 4px; @@ -708,7 +709,6 @@ .filters input[type="button"] { padding: 4px 6px; border: none; - margin-left: 4px; margin-right: 4px; border-radius: 4px; font-size: 12px; @@ -718,6 +718,7 @@ text-overflow: ellipsis; overflow: hidden; cursor: pointer; + min-width: 0px; width: 25%; } .filters input[type="button"]:hover { diff --git a/static/style/style.css b/static/style/style.css index 0c969ce9..38a4abce 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -688,6 +688,7 @@ display: flex; min-width: 50%; margin-left: 2px; + gap: 4px; } .filters input[type="text"] { padding: 4px; @@ -708,7 +709,6 @@ .filters input[type="button"] { padding: 4px 6px; border: none; - margin-left: 4px; margin-right: 4px; border-radius: 4px; font-size: 12px; @@ -718,6 +718,7 @@ text-overflow: ellipsis; overflow: hidden; cursor: pointer; + min-width: 0px; width: 25%; } .filters input[type="button"]:hover { From 1994d19bd351ec4de4a37e16f4881b8b0ae8196f Mon Sep 17 00:00:00 2001 From: koya0 Date: Sat, 4 Jan 2025 02:36:59 -0300 Subject: [PATCH 09/11] fix: increase margin-left of filters div in light mode --- static/style/inverted-style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index 0f2a069a..3ea3e633 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -6,7 +6,7 @@ width: 48px; } .filters { - width: 100%; + width: 100% !important; } #bottom-right { display: none; @@ -687,7 +687,7 @@ .filters { display: flex; min-width: 50%; - margin-left: 2px; + margin-left: 4px; gap: 4px; } .filters input[type="text"] { From f144ed02dad5b8402a26362d5857d3a3e923ab2d Mon Sep 17 00:00:00 2001 From: koya0 Date: Sat, 4 Jan 2025 02:49:31 -0300 Subject: [PATCH 10/11] fix: remove !important from filters width in light mode --- static/style/inverted-style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index 3ea3e633..a1b4e836 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -6,7 +6,7 @@ width: 48px; } .filters { - width: 100% !important; + width: 100%; } #bottom-right { display: none; From 22742821c48354d2ad6069ce7389144f351efd95 Mon Sep 17 00:00:00 2001 From: koya0 Date: Sun, 5 Jan 2025 00:21:56 -0300 Subject: [PATCH 11/11] style: refactor filters and media queries for improved layout in light mode --- static/style/inverted-style.css | 149 +++++++++++++++----------------- static/style/style.css | 149 +++++++++++++++----------------- 2 files changed, 140 insertions(+), 158 deletions(-) diff --git a/static/style/inverted-style.css b/static/style/inverted-style.css index a1b4e836..7bc2e392 100644 --- a/static/style/inverted-style.css +++ b/static/style/inverted-style.css @@ -1,57 +1,3 @@ -@media (orientation: portrait) or (max-width: 1050px) { - #filters { - display: none; - } - .filters-container label:not([for="view-toggle"]) { - width: 48px; - } - .filters { - width: 100%; - } - #bottom-right { - display: none; - } - #toolbar { - justify-content: space-between; - } - #bottom-bar { - display: flex; - height: 72px; - width: 100%; - overflow: hidden; - } - .preview-active #bottom-bar { - align-items: center; - } - .labels.cloned-labels { - display: none; - } - body.preview-active .labels.cloned-labels { - flex-grow: 1; - padding: 0px 6px; - display: flex; - width: 0%; - } - #filters-bottom { - flex-direction: column; - gap: 4px; - } - .labels { - margin: 0; - align-items: center; - width: 100%; - } - #filter-bottom { - max-width: 100%; - margin: 0; - } -} -@media (orientation: landscape) and (width > 1050px) { - #bottom-bar, - #filters-bottom { - display: none; - } -} @media (prefers-color-scheme: light) { :root { --grid-background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABYWlDQ1BrQ0dDb2xvclNwYWNlRGlzcGxheVAzAAAokWNgYFJJLCjIYWFgYMjNKykKcndSiIiMUmB/yMAOhLwMYgwKicnFBY4BAT5AJQwwGhV8u8bACKIv64LMOiU1tUm1XsDXYqbw1YuvRJsw1aMArpTU4mQg/QeIU5MLikoYGBhTgGzl8pICELsDyBYpAjoKyJ4DYqdD2BtA7CQI+whYTUiQM5B9A8hWSM5IBJrB+API1klCEk9HYkPtBQFul8zigpzESoUAYwKuJQOUpFaUgGjn/ILKosz0jBIFR2AopSp45iXr6SgYGRiaMzCAwhyi+nMgOCwZxc4gxJrvMzDY7v////9uhJjXfgaGjUCdXDsRYhoWDAyC3AwMJ3YWJBYlgoWYgZgpLY2B4dNyBgbeSAYG4QtAPdHFacZGYHlGHicGBtZ7//9/VmNgYJ/MwPB3wv//vxf9//93MVDzHQaGA3kAFSFl7jXH0fsAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAwf1XlwAAACNJREFUSA3t0IEAAAAMBKFHm7/UTaQQWnXDgAEDBgwYMGDgAXaJAz4RVVHYAAAAAElFTkSuQmCC"); @@ -241,7 +187,7 @@ .labels > img { margin-left: 4px; } - label:not([for="view-toggle"]) { + label:not([for="view-toggle"]), .filters input[type="button"] { line-height: 1.25; padding: 4px 6px; border-radius: 4px; @@ -283,7 +229,7 @@ input[type="radio"]:checked + label:not([for="view-toggle"]) { background-color: #7f7f7f80 !important; } - .labels { + .labels, .filters { display: flex; margin-left: 2px; justify-content: flex-end; @@ -435,7 +381,7 @@ display: none; } } - @media screen and (max-width: 1361px) { + @media screen and (max-width: 1385px) { .partner { margin-top: 0; } @@ -684,12 +630,6 @@ /* width: 100%; */ /* justify-content: normal; */ } - .filters { - display: flex; - min-width: 50%; - margin-left: 4px; - gap: 4px; - } .filters input[type="text"] { padding: 4px; border: none; @@ -697,7 +637,19 @@ background-color: #7f7f7f20; height: 16px; text-align: center; - width: 75%; + } + .filters input[type="button"] { + box-sizing: content-box; + border: none; + width: 88px; + cursor: pointer; + } + #filter-availability-top { + margin-right: 4px; + } + #filter-top { + width: calc(80vw / 3); + margin-right: 2px; } .filters input[type="text"]::placeholder { font-size: 12px; @@ -706,21 +658,6 @@ .filters input[type="text"].hidden { display: none; } - .filters input[type="button"] { - padding: 4px 6px; - border: none; - margin-right: 4px; - border-radius: 4px; - font-size: 12px; - text-align: center; - background-color: #7f7f7f20; - letter-spacing: 0.5px; - text-overflow: ellipsis; - overflow: hidden; - cursor: pointer; - min-width: 0px; - width: 25%; - } .filters input[type="button"]:hover { background-color: #7f7f7f40; } @@ -981,3 +918,57 @@ border-radius: 4px; } } + +@media (orientation: portrait) or (max-width: 1060px) { + #filters { + display: none; + } + .filters-container label:not([for="view-toggle"]), .filters input[type="button"] { + width: 48px; + } + #bottom-right { + display: none; + } + #toolbar { + justify-content: space-between; + } + #bottom-bar { + display: flex; + height: 72px; + width: 100%; + overflow: hidden; + } + .preview-active #bottom-bar { + align-items: center; + } + .labels.cloned-labels { + display: none; + } + body.preview-active .labels.cloned-labels { + flex-grow: 1; + padding: 0px 6px; + display: flex; + width: 0%; + } + #filters-bottom { + flex-direction: column; + gap: 4px; + } + .labels, .filters { + display: flex; + margin: 0; + align-items: center; + width: 100%; + } + #filter-bottom { + width: 180px; + flex-grow: 12; + margin: 0 2px 0; + } +} +@media (orientation: landscape) and (width > 1060px) { + #bottom-bar, + #filters-bottom { + display: none; + } +} diff --git a/static/style/style.css b/static/style/style.css index 38a4abce..c33b86a5 100644 --- a/static/style/style.css +++ b/static/style/style.css @@ -1,57 +1,3 @@ -@media (orientation: portrait) or (max-width: 1050px) { - #filters { - display: none; - } - .filters-container label:not([for="view-toggle"]) { - width: 48px; - } - .filters { - width: 100%; - } - #bottom-right { - display: none; - } - #toolbar { - justify-content: space-between; - } - #bottom-bar { - display: flex; - height: 72px; - width: 100%; - overflow: hidden; - } - .preview-active #bottom-bar { - align-items: center; - } - .labels.cloned-labels { - display: none; - } - body.preview-active .labels.cloned-labels { - flex-grow: 1; - padding: 0px 6px; - display: flex; - width: 0%; - } - #filters-bottom { - flex-direction: column; - gap: 4px; - } - .labels { - margin: 0; - align-items: center; - width: 100%; - } - #filter-bottom { - max-width: 100%; - margin: 0; - } -} -@media (orientation: landscape) and (width > 1050px) { - #bottom-bar, - #filters-bottom { - display: none; - } -} @media (prefers-color-scheme: dark) { :root { --grid-background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABYWlDQ1BrQ0dDb2xvclNwYWNlRGlzcGxheVAzAAAokWNgYFJJLCjIYWFgYMjNKykKcndSiIiMUmB/yMAOhLwMYgwKicnFBY4BAT5AJQwwGhV8u8bACKIv64LMOiU1tUm1XsDXYqbw1YuvRJsw1aMArpTU4mQg/QeIU5MLikoYGBhTgGzl8pICELsDyBYpAjoKyJ4DYqdD2BtA7CQI+whYTUiQM5B9A8hWSM5IBJrB+API1klCEk9HYkPtBQFul8zigpzESoUAYwKuJQOUpFaUgGjn/ILKosz0jBIFR2AopSp45iXr6SgYGRiaMzCAwhyi+nMgOCwZxc4gxJrvMzDY7v////9uhJjXfgaGjUCdXDsRYhoWDAyC3AwMJ3YWJBYlgoWYgZgpLY2B4dNyBgbeSAYG4QtAPdHFacZGYHlGHicGBtZ7//9/VmNgYJ/MwPB3wv//vxf9//93MVDzHQaGA3kAFSFl7jXH0fsAAAA4ZVhJZk1NACoAAAAIAAGHaQAEAAAAAQAAABoAAAAAAAKgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAwf1XlwAAACNJREFUSA3t0IEAAAAMBKFHm7/UTaQQWnXDgAEDBgwYMGDgAXaJAz4RVVHYAAAAAElFTkSuQmCC"); @@ -241,7 +187,7 @@ .labels > img { margin-left: 4px; } - label:not([for="view-toggle"]) { + label:not([for="view-toggle"]), .filters input[type="button"] { line-height: 1.25; padding: 4px 6px; border-radius: 4px; @@ -283,7 +229,7 @@ input[type="radio"]:checked + label:not([for="view-toggle"]) { background-color: #80808080 !important; } - .labels { + .labels, .filters { display: flex; margin-left: 2px; justify-content: flex-end; @@ -435,7 +381,7 @@ display: none; } } - @media screen and (max-width: 1361px) { + @media screen and (max-width: 1385px) { .partner { margin-top: 0; } @@ -684,12 +630,6 @@ /* width: 100%; */ /* justify-content: normal; */ } - .filters { - display: flex; - min-width: 50%; - margin-left: 2px; - gap: 4px; - } .filters input[type="text"] { padding: 4px; border: none; @@ -697,7 +637,19 @@ background-color: #80808020; height: 16px; text-align: center; - width: 75%; + } + .filters input[type="button"] { + box-sizing: content-box; + border: none; + width: 88px; + cursor: pointer; + } + #filter-availability-top { + margin-right: 4px; + } + #filter-top { + width: calc(80vw / 3); + margin-right: 2px; } .filters input[type="text"]::placeholder { font-size: 12px; @@ -706,21 +658,6 @@ .filters input[type="text"].hidden { display: none; } - .filters input[type="button"] { - padding: 4px 6px; - border: none; - margin-right: 4px; - border-radius: 4px; - font-size: 12px; - text-align: center; - background-color: #80808020; - letter-spacing: 0.5px; - text-overflow: ellipsis; - overflow: hidden; - cursor: pointer; - min-width: 0px; - width: 25%; - } .filters input[type="button"]:hover { background-color: #80808040; } @@ -981,3 +918,57 @@ border-radius: 4px; } } + +@media (orientation: portrait) or (max-width: 1060px) { + #filters { + display: none; + } + .filters-container label:not([for="view-toggle"]), .filters input[type="button"] { + width: 48px; + } + #bottom-right { + display: none; + } + #toolbar { + justify-content: space-between; + } + #bottom-bar { + display: flex; + height: 72px; + width: 100%; + overflow: hidden; + } + .preview-active #bottom-bar { + align-items: center; + } + .labels.cloned-labels { + display: none; + } + body.preview-active .labels.cloned-labels { + flex-grow: 1; + padding: 0px 6px; + display: flex; + width: 0%; + } + #filters-bottom { + flex-direction: column; + gap: 4px; + } + .labels, .filters { + display: flex; + margin: 0; + align-items: center; + width: 100%; + } + #filter-bottom { + width: 180px; + flex-grow: 12; + margin: 0 2px 0; + } +} +@media (orientation: landscape) and (width > 1060px) { + #bottom-bar, + #filters-bottom { + display: none; + } +}