Add search

dev
gravel 11 months ago
parent e2bed618b8
commit c087cc9436
Signed by: gravel
GPG Key ID: C0538F3C906B308F

@ -46,10 +46,12 @@
html {
font-size: clamp(12px, 2vw, var(--max-font-size-unitless) * 1px);
height: 100%;
}
body {
margin: 0;
height: 100%;
}
#toggle-theme-switch {
@ -57,8 +59,10 @@ body {
}
#theming-root {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
min-height: 100%;
margin: 0;
background-color: var(--secondary-color);
color: var(--primary-color);
@ -171,6 +175,43 @@ header {
flex-grow: 1;
}
#search-container {
display: flex;
justify-content: center;
box-sizing: border-box;
height: 0;
overflow: hidden;
transition: height 0.25s;
}
#toggle-search-bar:checked ~ #search-container {
height: 3rem;
}
#toggle-search-bar:not(:checked) ~ #search-container > * {
display: none;
}
#search {
display: flex;
justify-content: center;
align-items: baseline;
}
#search-bar {
height: 1.25rem;
color: var(--primary-color);
background-color: var(--secondary-color);
border: 1px var(--primary-color) solid;
text-align: right;
padding: 0.1rem 0.25rem;
margin-right: 1rem;
}
#search-bar.search-no-results {
color: red;
}
/* --- Table --- */
#tbl_communities {
@ -402,6 +443,10 @@ a[href^="https:"] .protocol-indicator::after {
/* --- Footer --- */
#footer-divider {
width: 90%;
}
footer {
display: flex;
flex-direction: column;

@ -22,7 +22,8 @@ export const dom = {
hostname: row.getAttribute(ATTRIBUTES.ROW.HOSTNAME),
public_key: row.getAttribute(ATTRIBUTES.ROW.PUBLIC_KEY),
staff: row.getAttribute(ATTRIBUTES.ROW.STAFF_DATA),
tags: row.getAttribute(ATTRIBUTES.ROW.TAGS),
/** @type {{type: string, text: string, description: string}[]} */
tags: JSON.parse(row.getAttribute(ATTRIBUTES.ROW.TAGS)),
icon: row.getAttribute(ATTRIBUTES.ROW.ROOM_ICON),
has_icon: row.getAttribute(ATTRIBUTES.ROW.ROOM_ICON).trim() != "",
icon_safety: row.getAttribute(ATTRIBUTES.ROW.ROOM_ICON_SAFETY),
@ -41,6 +42,11 @@ export const dom = {
servers_hidden: () => document.getElementById("servers_hidden"),
snackbar: () => document.getElementById("copy-snackbar"),
qr_code_buttons: () => document.querySelectorAll('.qr-code-button'),
/** @return {HTMLInputElement | null} */
toggle_search_checkbox: () => document.querySelector('#toggle-search-bar'),
/** @return {HTMLInputElement | null} */
search_bar: () => document.querySelector('#search-bar'),
btn_clear_search: () => document.querySelector("#btn-clear-search")
}
export const JOIN_URL_PASTE = "Copied URL to clipboard. Paste into Session app to join";
@ -92,6 +98,12 @@ export const ATTRIBUTES = {
}
};
export const CLASSES = {
SEARCH: {
NO_RESULTS: 'search-no-results'
}
}
export function columnAscendingByDefault(column) {
return column != COLUMN.USERS;
}

@ -17,7 +17,7 @@
import {
dom, COLUMN, COLUMN_LITERAL, COMPARISON, ATTRIBUTES,
columnAscendingByDefault, columnIsSortable, COLUMN_TRANSFORMATION,
element, JOIN_URL_PASTE, communityQRCodeURL, STAFF_ID_PASTE, IDENTIFIER_PASTE, DETAILS_LINK_PASTE
element, JOIN_URL_PASTE, communityQRCodeURL, STAFF_ID_PASTE, IDENTIFIER_PASTE, DETAILS_LINK_PASTE, CLASSES
} from './js/constants.js';
// Hidden communities for transparency.
@ -129,16 +129,26 @@ function onLoad() {
hideBadCommunities();
// Sort by server to show off new feature & align colors.
sortTable(COLUMN.SERVER_ICON);
initializeSearch();
createJoinLinkButtons();
markSortableColumns();
addQRModalHandlers();
addServerIconInteractions();
addSearchInteractions();
preloadImages();
setInterval(() => {
preloadImages();
}, 60 * 60E3);
reactToURLParameters();
addInformativeInteractions();
Array.from(document.querySelectorAll('.enter-clicks')).forEach(element => {
// @ts-ignore
element.addEventListener('keydown', (/** @type {KeyboardEvent} */ ev) => {
if (ev.key == "Enter") {
ev.currentTarget.click();
}
})
})
}
/**
@ -200,7 +210,7 @@ function displayQRModal(communityID, pane = 0) {
tagContainer.innerHTML = "";
tagContainer.append(
...JSON.parse(rowInfo.tags).map(tag => tagBody(tag))
...rowInfo.tags.map(tag => tagBody(tag))
);
dom.details_modal_qr_code().src = communityQRCodeURL(communityID);
@ -438,6 +448,29 @@ function addServerIconInteractions() {
}
}
function addSearchInteractions() {
dom.toggle_search_checkbox()?.addEventListener('click', function (ev) {
if (this.checked) {
dom.search_bar()?.focus();
} else {
useSearchTerm("");
}
})
dom.search_bar()?.addEventListener('keydown', function () {
setTimeout(() => useSearchTerm(this.value), 0);
})
dom.search_bar()?.addEventListener('keyup', function () {
useSearchTerm(this.value);
})
dom.btn_clear_search()?.addEventListener('click', function () {
useSearchTerm("");
dom.search_bar().value = "";
})
}
/**
* Function comparing two elements.
*
@ -562,25 +595,73 @@ function markSortableColumns() {
};
}
/**
* @type {HTMLTableRowElement[]}
*/
const communityFullRowCache = [];
function initializeSearch() {
communityFullRowCache.push(...dom.tbl_communities_content_rows());
}
/**
*
* @param {string} [rawTerm]
*/
function useSearchTerm(rawTerm) {
if (!rawTerm) {
replaceRowsWith(communityFullRowCache);
} else {
const term = rawTerm.toLowerCase();
const termTags = Array.from(rawTerm.matchAll(/#[^#\s]+/g)).map(match => match[0].slice(1).toLowerCase());
const newRows = communityFullRowCache.filter(
row => {
const rowInfo = dom.row_info(row);
const rowTags = rowInfo.tags.map(({text}) => text);
return rowInfo.name.toLowerCase().includes(term) ||
rowInfo.description.toLowerCase().includes(term) ||
(termTags.length >= 1 && termTags.some(tag => rowTags.some(rowTag => rowTag.includes(tag))))
}
);
if (newRows.length === 0) {
dom.search_bar()?.classList.add(CLASSES.SEARCH.NO_RESULTS);
} else {
dom.search_bar()?.classList.remove(CLASSES.SEARCH.NO_RESULTS);
}
replaceRowsWith(newRows);
}
sortTable();
}
function replaceRowsWith(rows) {
dom.tbl_communities_content_rows().forEach(row => row.remove());
dom.tbl_communities().querySelector("tbody").append(...rows);
}
/**
* Sorts the default communities table according the given column.
* Sort direction is determined by defaults; successive sorts
* on the same column reverse the sort direction.
* @param {number} column - Numeric ID of column being sorted.
* @param {number} [column] - Numeric ID of column being sorted. Re-applies last sort if absent.
*/
function sortTable(column) {
const table = dom.tbl_communities();
const sortState = getSortState(table);
const sortingAsBefore = column === undefined;
const sortingNewColumn = column !== sortState?.column;
const ascending = sortingNewColumn
? columnAscendingByDefault(column)
: !sortState.ascending;
const compare = makeRowComparer(column, ascending);
const sortedColumn = column ?? sortState?.column;
const ascending =
sortingAsBefore ?
sortState.ascending : (
sortingNewColumn
? columnAscendingByDefault(column)
: !sortState.ascending
);
const compare = makeRowComparer(sortedColumn, ascending);
const rows = Array.from(table.rows).slice(1);
rows.sort(compare);
rows.forEach((row) => row.remove());
table.querySelector("tbody").append(...rows);
setSortState(table, { ascending, column });
replaceRowsWith(rows);
setSortState(table, { ascending, column: sortedColumn });
}
// `html.js` selector for styling purposes

@ -65,10 +65,16 @@
<div id="header-start"></div>
<div id="header-end">
<a
id="link-about"
href="#footer"
title="Learn more about sessioncommunities.online."
id="link-about"
href="#footer"
title="Learn more about sessioncommunities.online."
>About</a>
<label
for="toggle-search-bar"
class="anchorstyle clickable enter-clicks js-only"
title="Open search bar."
tabindex="0"
>Search</label>
<a
id="link-more-sites"
href="#more-sites"
@ -76,7 +82,7 @@
>More groups</a>
<label
for="toggle-theme-switch"
class="anchorstyle clickable"
class="anchorstyle clickable enter-clicks"
title="Switch color theme"
tabindex="0"
>Switch theme</label>
@ -90,11 +96,23 @@
</div>
</header>
<h1 id="headline">Session Communities</h1>
<input id="toggle-search-bar" class="hidden" type="checkbox">
<div id="search-container">
<div id="search">
<input id="search-bar" type="text" placeholder="Search with words, #tags">
<span id="btn-clear-search" class="anchorstyle clickable enter-clicks" tabindex="0" title="Clear search">×</span>
</div>
</div>
<?php include "+components/qr-modals.php" ?>
<?php include "+components/tbl-communities.php" ?>
<hr>
<gap></gap>
<hr id="footer-divider">
<footer id="footer">
<p id="server_summary">
@ -193,9 +211,10 @@
>oxen.directory</a
><span
id="more-sites-info-button"
class="clickable"
class="clickable enter-clicks"
href="#"
title="Read more about sites hosting additional groups."
tabindex="0"
>()</span>
</nav>
<nav id="about-session" class="highlight">

Loading…
Cancel
Save