mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-14 05:53:47 -06:00
feat: list long file pages as filtered tables
MAME's card pages, GroovyMAME and yaps2 read 13,000 to 16,700 words of cards. Each entry is now a table row (name, members, status, short hash) that opens to its card in a details block, with the site's filter box and row counter. Pages from 150 entries and every split part use it. Visible words: mame-files-1 16,680 to 1,612, groovymame 14,396 to 1,876. A row costs about five elements, so a part holds 180 cards: MAME goes from 8 parts to 9, the largest at 567 KB and 8,989 elements. Each wanted list (TOSEC, No-Intro, Redump) opens on its counts, then one table folded under a filter box that opens it, in place of a block per DAT. Only the names are searched: indexed descriptions and hashes put the PlayStation page ahead of the PlayStation 2 one. A filtered row stayed visible on a phone: a stacked row's display:block outweighed the hidden attribute on every stacked table.
This commit is contained in:
1 parent
7ec4d00375
commit
1409a8db6a
8 files changed
+658
-28
No files matched your search
@@ -87,9 +87,19 @@ const setScrollable = (table: HTMLTableElement, overflows: boolean) => {
|
||||
// The filter box above a long table is written when the page is built
|
||||
// (src/plugins/rehype-stack-tables.mjs), so the table never moves down once
|
||||
// drawn. Here it only filters.
|
||||
const filterTable = (table: HTMLTableElement) => {
|
||||
// A table folded in a closed block can have its box above the block
|
||||
// (the provenance lists): typing opens the block on the rows it keeps.
|
||||
const filterControls = (table: HTMLTableElement) => {
|
||||
const controls = table.previousElementSibling;
|
||||
if (!controls?.matches('.rb-table-filter')) return;
|
||||
if (controls?.matches('.rb-table-filter')) return controls;
|
||||
const block = table.closest('details');
|
||||
return block?.previousElementSibling?.matches('.rb-table-filter') ? block.previousElementSibling : null;
|
||||
};
|
||||
|
||||
const filterTable = (table: HTMLTableElement) => {
|
||||
const controls = filterControls(table);
|
||||
if (!controls) return;
|
||||
const block = controls.nextElementSibling instanceof HTMLDetailsElement ? controls.nextElementSibling : null;
|
||||
const input = controls.querySelector('input');
|
||||
const count = controls.querySelector('.rb-table-filter-count');
|
||||
if (!input || !count || input.dataset.rbWired) return;
|
||||
@@ -100,6 +110,7 @@ const filterTable = (table: HTMLTableElement) => {
|
||||
input.addEventListener('input', () => {
|
||||
searchable ??= rows.map((row) => ({ row, text: row.textContent!.normalize('NFKD').toLocaleLowerCase() }));
|
||||
const query = input.value.trim().normalize('NFKD').toLocaleLowerCase();
|
||||
if (block && query) block.open = true;
|
||||
let visible = 0;
|
||||
for (const entry of searchable) {
|
||||
entry.row.hidden = !!query && !entry.text.includes(query);
|
||||
@@ -171,6 +182,9 @@ const enhanceTables = () => {
|
||||
});
|
||||
if (document.readyState === 'complete') start();
|
||||
else addEventListener('load', start, { once: true });
|
||||
// A box above a closed block is typed in before its table is ever near
|
||||
// the screen: it is wired now.
|
||||
for (const table of tables) if (table.closest('details:not([open])') && filterControls(table)) filterTable(table);
|
||||
let timer = 0;
|
||||
addEventListener('resize', () => {
|
||||
clearTimeout(timer);
|
||||
@@ -743,6 +757,18 @@ const followMovedCard = () => {
|
||||
if (match && !target) location.replace(new URL(`files/?sha1=${match[1]}`, siteRoot()));
|
||||
};
|
||||
|
||||
// A link to a card folded in a table row (emulators with many entries)
|
||||
// opens its row. Chrome does it on its own. Where the browser left the
|
||||
// target hidden, the same address is followed again once the row is open,
|
||||
// so the browser brings the card into view as for any link.
|
||||
const openTargetBlock = () => {
|
||||
const id = decodeURIComponent(location.hash.slice(1));
|
||||
const block = id ? document.getElementById(id)?.closest('details') : null;
|
||||
if (!block || block.open) return;
|
||||
block.open = true;
|
||||
location.replace(location.hash);
|
||||
};
|
||||
|
||||
// The site search holds no hashes. A hash typed in it gets "Look up this
|
||||
// hash" as its first result, and Enter opens the lookup. The pages Pagefind
|
||||
// finds for the same characters (a file name that holds them, a word that
|
||||
@@ -948,6 +974,8 @@ const notFound = () => {
|
||||
|
||||
resolveFileAddress();
|
||||
followMovedCard();
|
||||
openTargetBlock();
|
||||
addEventListener('hashchange', openTargetBlock);
|
||||
enhanceTables();
|
||||
breakPaths();
|
||||
hashSearch();
|
||||
|
||||
Reference in new issue
Block a user