auto-commit via WEVIA vault_git intent 2026-04-19T14:36:24+00:00
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"generated_at": "2026-04-19T16:30:01.731795",
|
||||
"generated_at": "2026-04-19T16:35:01.533191",
|
||||
"stats": {
|
||||
"total": 444,
|
||||
"pending": 849,
|
||||
"total": 445,
|
||||
"pending": 851,
|
||||
"kaouther_surfaced": 29,
|
||||
"chrome_surfaced": 10,
|
||||
"notif_only_done": 0,
|
||||
"autofix_archived": 0,
|
||||
"cerebras_archived": 0,
|
||||
"older_3d_archived": 0,
|
||||
"unknown": 405,
|
||||
"unknown": 406,
|
||||
"errors": 0
|
||||
},
|
||||
"actions": [
|
||||
|
||||
13
api/v76-scripts/orphans-audit.sh
Executable file
13
api/v76-scripts/orphans-audit.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
# V79 orphans-audit agent script
|
||||
curl -sk --max-time 3 'http://127.0.0.1:5890/api/wevia-pages-registry.php?action=orphans' -H 'Host: weval-consulting.com' 2>/dev/null | python3 -c "
|
||||
import sys, json
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
print(f'orphans:{d[\"count\"]}')
|
||||
top5 = list(d['orphans'].items())[:5]
|
||||
for name, meta in top5:
|
||||
print(f' {meta[\"class\"]}: {name}')
|
||||
except:
|
||||
print('orphans:ERR')
|
||||
"
|
||||
10
api/v76-scripts/pages-index.sh
Executable file
10
api/v76-scripts/pages-index.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# V79 pages-index agent script
|
||||
curl -sk --max-time 3 'http://127.0.0.1:5890/api/wevia-pages-registry.php?action=summary' -H 'Host: weval-consulting.com' 2>/dev/null | python3 -c "
|
||||
import sys, json
|
||||
try:
|
||||
d = json.load(sys.stdin)
|
||||
print(f'total:{d[\"total_pages\"]} ref:{d[\"referenced_pages\"]} orph:{d[\"orphans_count\"]} links:{d[\"links_count\"]} cls:{len(d[\"classes\"])}')
|
||||
except Exception as e:
|
||||
print('pages_index:ERR')
|
||||
"
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"ok": true,
|
||||
"version": "V83-business-kpi",
|
||||
"ts": "2026-04-19T14:34:45+00:00",
|
||||
"ts": "2026-04-19T14:35:45+00:00",
|
||||
"summary": {
|
||||
"total_categories": 7,
|
||||
"total_kpis": 56,
|
||||
|
||||
206
api/wevia-pages-registry.php
Normal file
206
api/wevia-pages-registry.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
/**
|
||||
* V79 — Pages Registry & Orphans Enricher
|
||||
*
|
||||
* Builds a live catalog of all HTML pages, classifies them,
|
||||
* identifies orphans, exposes via API & chat.
|
||||
*
|
||||
* ZERO modification des pages existantes.
|
||||
* ADDITIVE ONLY: nouvelle source de vérité pages.
|
||||
*
|
||||
* Endpoints:
|
||||
* GET /api/wevia-pages-registry.php?action=summary
|
||||
* GET /api/wevia-pages-registry.php?action=orphans
|
||||
* GET /api/wevia-pages-registry.php?action=full
|
||||
* GET /api/wevia-pages-registry.php?action=by_class&class=hub
|
||||
* GET /api/wevia-pages-registry.php?action=links_of&page=foo.html
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
||||
$HTML_DIR = '/var/www/html';
|
||||
$CACHE_FILE = '/tmp/wevia-pages-registry-cache.json';
|
||||
$CACHE_TTL = 300; // 5 min
|
||||
|
||||
function build_registry($dir) {
|
||||
$pages = [];
|
||||
$hrefs_by_page = [];
|
||||
$all_hrefs = [];
|
||||
|
||||
// Scan all .html files
|
||||
$files = glob($dir . '/*.html');
|
||||
foreach ($files as $file) {
|
||||
$name = basename($file);
|
||||
$pages[$name] = [
|
||||
'name' => $name,
|
||||
'path' => '/' . $name,
|
||||
'size_kb' => round(filesize($file) / 1024, 1),
|
||||
'mtime' => date('c', filemtime($file)),
|
||||
'class' => classify($name),
|
||||
'incoming_links' => 0,
|
||||
'outgoing_links' => 0,
|
||||
'orphan' => true, // will flip to false if referenced
|
||||
'title' => extract_title($file),
|
||||
];
|
||||
}
|
||||
|
||||
// Scan for hrefs
|
||||
foreach ($files as $file) {
|
||||
$name = basename($file);
|
||||
$content = @file_get_contents($file);
|
||||
if (!$content) continue;
|
||||
if (preg_match_all('/href=["\']([^"\'#?]+\.html)/', $content, $m)) {
|
||||
$outgoing = [];
|
||||
foreach ($m[1] as $target) {
|
||||
$target_name = basename($target);
|
||||
if (isset($pages[$target_name])) {
|
||||
$pages[$target_name]['incoming_links']++;
|
||||
$pages[$target_name]['orphan'] = false;
|
||||
$outgoing[] = $target_name;
|
||||
$all_hrefs[] = [$name, $target_name];
|
||||
}
|
||||
}
|
||||
$pages[$name]['outgoing_links'] = count(array_unique($outgoing));
|
||||
$hrefs_by_page[$name] = array_values(array_unique($outgoing));
|
||||
}
|
||||
}
|
||||
|
||||
// index.html is root entry, never orphan
|
||||
if (isset($pages['index.html'])) $pages['index.html']['orphan'] = false;
|
||||
|
||||
$orphans = array_filter($pages, function($p) { return $p['orphan']; });
|
||||
$top_referenced = $pages;
|
||||
uasort($top_referenced, function($a, $b) { return $b['incoming_links'] - $a['incoming_links']; });
|
||||
|
||||
return [
|
||||
'ts' => date('c'),
|
||||
'total_pages' => count($pages),
|
||||
'orphans_count' => count($orphans),
|
||||
'referenced_pages' => count($pages) - count($orphans),
|
||||
'orphans' => array_keys($orphans),
|
||||
'top_referenced' => array_slice(array_keys($top_referenced), 0, 20),
|
||||
'by_class' => group_by_class($pages),
|
||||
'links_count' => count($all_hrefs),
|
||||
'pages' => $pages,
|
||||
'hrefs_by_page' => $hrefs_by_page,
|
||||
];
|
||||
}
|
||||
|
||||
function classify($name) {
|
||||
if (strpos($name, 'index.html') !== false) return 'entry';
|
||||
if (strpos($name, 'hub') !== false) return 'hub';
|
||||
if (strpos($name, 'dashboard') !== false) return 'dashboard';
|
||||
if (strpos($name, 'archi') !== false || strpos($name, 'enterprise') !== false) return 'architecture';
|
||||
if (strpos($name, 'chart') !== false || strpos($name, 'visual') !== false || strpos($name, 'cartograph') !== false) return 'visualization';
|
||||
if (strpos($name, 'admin') !== false) return 'admin';
|
||||
if (strpos($name, 'wevia') !== false) return 'wevia';
|
||||
if (strpos($name, 'ethica') !== false) return 'ethica';
|
||||
if (strpos($name, 'paperclip') !== false) return 'paperclip';
|
||||
if (strpos($name, 'plan') !== false || strpos($name, 'strateg') !== false) return 'strategy';
|
||||
if (strpos($name, 'scout') !== false || strpos($name, 'arena') !== false || strpos($name, 'ops') !== false) return 'operations';
|
||||
if (strpos($name, 'crm') !== false || strpos($name, 'sales') !== false || strpos($name, 'deal') !== false) return 'business';
|
||||
if (strpos($name, 'test') !== false || strpos($name, 'demo') !== false) return 'test';
|
||||
if (strpos($name, 'tool') !== false) return 'tools';
|
||||
if (strpos($name, 'office') !== false) return 'office';
|
||||
if (strpos($name, 'deerflow') !== false) return 'deerflow';
|
||||
if (strpos($name, 'security') !== false) return 'security';
|
||||
if (strpos($name, 'monitoring') !== false || strpos($name, 'monitor') !== false) return 'monitoring';
|
||||
if (strpos($name, 'agent') !== false) return 'agents';
|
||||
if (strpos($name, 'api') !== false) return 'api_tools';
|
||||
return 'module';
|
||||
}
|
||||
|
||||
function group_by_class($pages) {
|
||||
$groups = [];
|
||||
foreach ($pages as $p) {
|
||||
$c = $p['class'];
|
||||
if (!isset($groups[$c])) $groups[$c] = ['count' => 0, 'orphans' => 0, 'pages' => []];
|
||||
$groups[$c]['count']++;
|
||||
if ($p['orphan']) $groups[$c]['orphans']++;
|
||||
$groups[$c]['pages'][] = $p['name'];
|
||||
}
|
||||
return $groups;
|
||||
}
|
||||
|
||||
function extract_title($file) {
|
||||
$content = @file_get_contents($file, false, null, 0, 2000);
|
||||
if (!$content) return '';
|
||||
if (preg_match('/<title>(.*?)<\/title>/is', $content, $m)) {
|
||||
return trim(html_entity_decode($m[1], ENT_QUOTES));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// Cache layer
|
||||
$action = $_GET['action'] ?? 'summary';
|
||||
$cached = null;
|
||||
|
||||
if (file_exists($CACHE_FILE) && (time() - filemtime($CACHE_FILE)) < $CACHE_TTL) {
|
||||
$cached = @json_decode(@file_get_contents($CACHE_FILE), true);
|
||||
}
|
||||
|
||||
if ($cached && empty($_GET['rebuild'])) {
|
||||
$data = $cached;
|
||||
$data['cached'] = true;
|
||||
} else {
|
||||
$data = build_registry($HTML_DIR);
|
||||
$data['cached'] = false;
|
||||
@file_put_contents($CACHE_FILE, json_encode($data, JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
// Action routing
|
||||
switch ($action) {
|
||||
case 'summary':
|
||||
echo json_encode([
|
||||
'ts' => $data['ts'],
|
||||
'total_pages' => $data['total_pages'],
|
||||
'orphans_count' => $data['orphans_count'],
|
||||
'referenced_pages' => $data['referenced_pages'],
|
||||
'links_count' => $data['links_count'],
|
||||
'cached' => $data['cached'],
|
||||
'classes' => array_map(function($c) { return ['count' => $c['count'], 'orphans' => $c['orphans']]; }, $data['by_class']),
|
||||
'top_referenced' => array_slice($data['top_referenced'], 0, 10),
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
case 'orphans':
|
||||
$orphan_details = [];
|
||||
foreach ($data['orphans'] as $o) {
|
||||
$orphan_details[$o] = [
|
||||
'class' => $data['pages'][$o]['class'],
|
||||
'size_kb' => $data['pages'][$o]['size_kb'],
|
||||
'title' => $data['pages'][$o]['title'],
|
||||
'mtime' => $data['pages'][$o]['mtime'],
|
||||
'outgoing_links' => $data['pages'][$o]['outgoing_links'],
|
||||
];
|
||||
}
|
||||
echo json_encode(['count' => count($data['orphans']), 'orphans' => $orphan_details], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
case 'by_class':
|
||||
$cls = $_GET['class'] ?? 'hub';
|
||||
if (!isset($data['by_class'][$cls])) { echo json_encode(['error'=>'class not found','classes'=>array_keys($data['by_class'])]); break; }
|
||||
echo json_encode($data['by_class'][$cls], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
case 'links_of':
|
||||
$page = $_GET['page'] ?? '';
|
||||
if (!$page || !isset($data['pages'][$page])) { echo json_encode(['error'=>'page not found']); break; }
|
||||
$incoming = [];
|
||||
foreach ($data['hrefs_by_page'] as $src => $targets) {
|
||||
if (in_array($page, $targets)) $incoming[] = $src;
|
||||
}
|
||||
echo json_encode([
|
||||
'page' => $page,
|
||||
'class' => $data['pages'][$page]['class'],
|
||||
'orphan' => $data['pages'][$page]['orphan'],
|
||||
'incoming_links' => $data['pages'][$page]['incoming_links'],
|
||||
'incoming_from' => $incoming,
|
||||
'outgoing_links' => $data['pages'][$page]['outgoing_links'],
|
||||
'outgoing_to' => $data['hrefs_by_page'][$page] ?? [],
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
case 'full':
|
||||
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
default:
|
||||
echo json_encode(['error'=>'unknown action','actions'=>['summary','orphans','by_class','links_of','full']]);
|
||||
}
|
||||
262
pages-index.html
Normal file
262
pages-index.html
Normal file
@@ -0,0 +1,262 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pages Index · WEVAL · 251 pages · 0 orphelin</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg-0: #0a0e1a;
|
||||
--bg-1: #111827;
|
||||
--bg-2: #1a2333;
|
||||
--txt-0: #f1f5f9;
|
||||
--txt-1: #94a3b8;
|
||||
--txt-2: #64748b;
|
||||
--accent: #6366f1;
|
||||
--accent-hot: #f59e0b;
|
||||
--ok: #10b981;
|
||||
--warn: #f59e0b;
|
||||
--err: #ef4444;
|
||||
--border: #1f2937;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
background: linear-gradient(135deg, var(--bg-0), var(--bg-1));
|
||||
color: var(--txt-0);
|
||||
font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
min-height: 100vh;
|
||||
}
|
||||
header {
|
||||
padding: 32px 40px;
|
||||
background: linear-gradient(90deg, rgba(99,102,241,.08), transparent);
|
||||
border-bottom: 1px solid var(--border);
|
||||
backdrop-filter: blur(10px);
|
||||
position: sticky; top: 0; z-index: 10;
|
||||
}
|
||||
h1 { font-size: 28px; font-weight: 700; letter-spacing: -0.02em; }
|
||||
h1 span { color: var(--accent); }
|
||||
.sub { color: var(--txt-1); font-size: 13px; margin-top: 4px; }
|
||||
.stats {
|
||||
display: flex; gap: 32px; margin-top: 20px;
|
||||
}
|
||||
.stat {
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
.stat-val { font-size: 24px; font-weight: 700; color: var(--accent); }
|
||||
.stat-lbl { font-size: 11px; color: var(--txt-2); text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
.search {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
padding: 14px 18px;
|
||||
background: var(--bg-2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
color: var(--txt-0);
|
||||
font-size: 14px;
|
||||
transition: border-color .2s;
|
||||
}
|
||||
.search:focus { outline: none; border-color: var(--accent); }
|
||||
.container { padding: 32px 40px; max-width: 1600px; margin: 0 auto; }
|
||||
.class-section {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.class-title {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
font-size: 18px; font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.class-title .icon { font-size: 22px; }
|
||||
.class-title .count { color: var(--txt-1); font-size: 13px; font-weight: 400; }
|
||||
.class-title .orph-flag { color: var(--warn); font-size: 12px; font-weight: 500; }
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.card {
|
||||
background: var(--bg-2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: transform .15s, border-color .15s;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.card:hover { transform: translateY(-2px); border-color: var(--accent); }
|
||||
.card.orphan::before {
|
||||
content: '';
|
||||
position: absolute; top: 0; left: 0;
|
||||
width: 4px; height: 100%;
|
||||
background: var(--warn);
|
||||
}
|
||||
.card.top::before {
|
||||
content: '';
|
||||
position: absolute; top: 0; left: 0;
|
||||
width: 4px; height: 100%;
|
||||
background: var(--ok);
|
||||
}
|
||||
.card-name {
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.card-meta {
|
||||
font-size: 11px;
|
||||
color: var(--txt-2);
|
||||
display: flex; gap: 10px;
|
||||
}
|
||||
.meta-in, .meta-out { display: flex; align-items: center; gap: 3px; }
|
||||
.meta-in::before { content: '↓'; color: var(--ok); }
|
||||
.meta-out::before { content: '↑'; color: var(--accent); }
|
||||
.card.orphan .meta-in::before { color: var(--warn); }
|
||||
.loading { text-align: center; padding: 60px; color: var(--txt-1); }
|
||||
.hidden { display: none !important; }
|
||||
footer {
|
||||
padding: 20px 40px;
|
||||
text-align: center;
|
||||
color: var(--txt-2);
|
||||
font-size: 12px;
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: 60px;
|
||||
}
|
||||
footer a { color: var(--accent); text-decoration: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Pages Index · <span>WEVAL Technology Platform</span></h1>
|
||||
<div class="sub">Référentiel unifié · toutes les pages de l'architecture · liens de navigation live</div>
|
||||
<div class="stats">
|
||||
<div class="stat"><div class="stat-val" id="stat-total">—</div><div class="stat-lbl">Pages totales</div></div>
|
||||
<div class="stat"><div class="stat-val" id="stat-ref">—</div><div class="stat-lbl">Reliées</div></div>
|
||||
<div class="stat"><div class="stat-val" id="stat-orph" style="color:var(--warn)">—</div><div class="stat-lbl">Orphelines</div></div>
|
||||
<div class="stat"><div class="stat-val" id="stat-links">—</div><div class="stat-lbl">Liens totaux</div></div>
|
||||
<div class="stat"><div class="stat-val" id="stat-classes">—</div><div class="stat-lbl">Catégories</div></div>
|
||||
</div>
|
||||
<input class="search" id="search" placeholder="🔍 Rechercher une page (nom / titre / catégorie) ..." autofocus>
|
||||
</header>
|
||||
<div class="container" id="main">
|
||||
<div class="loading">Chargement du registre...</div>
|
||||
</div>
|
||||
<footer>
|
||||
Source de vérité live · <a href="/api/wevia-pages-registry.php?action=summary" target="_blank">API Summary</a> ·
|
||||
<a href="/api/wevia-pages-registry.php?action=orphans" target="_blank">Orphans</a> ·
|
||||
<a href="/api/wevia-pages-registry.php?action=full" target="_blank">Full JSON</a> ·
|
||||
<a href="/wevia-master.html">Retour WEVIA Master</a>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
const ICONS = {
|
||||
entry: '🏠', hub: '🔗', dashboard: '📊', architecture: '🏛️',
|
||||
visualization: '📈', admin: '⚙️', wevia: '🤖', ethica: '⚕️',
|
||||
paperclip: '📎', strategy: '🎯', operations: '⚡', business: '💼',
|
||||
test: '🧪', tools: '🛠️', office: '🏢', deerflow: '🦌',
|
||||
security: '🔐', monitoring: '📡', agents: '👥', api_tools: '🔌',
|
||||
module: '📄'
|
||||
};
|
||||
|
||||
const CLASS_ORDER = [
|
||||
'entry','hub','dashboard','architecture','wevia','ethica','agents','paperclip',
|
||||
'operations','business','strategy','tools','office','monitoring','security',
|
||||
'visualization','admin','deerflow','api_tools','test','module'
|
||||
];
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
const r = await fetch('/api/wevia-pages-registry.php?action=full&rebuild=1');
|
||||
const d = await r.json();
|
||||
render(d);
|
||||
} catch (e) {
|
||||
document.getElementById('main').innerHTML = '<div class="loading" style="color:var(--err)">Erreur: ' + e.message + '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
function render(d) {
|
||||
// Stats
|
||||
document.getElementById('stat-total').textContent = d.total_pages;
|
||||
document.getElementById('stat-ref').textContent = d.referenced_pages;
|
||||
document.getElementById('stat-orph').textContent = d.orphans_count;
|
||||
document.getElementById('stat-links').textContent = d.links_count;
|
||||
document.getElementById('stat-classes').textContent = Object.keys(d.by_class).length;
|
||||
|
||||
// Group pages
|
||||
const pages = d.pages;
|
||||
const byClass = {};
|
||||
for (const name in pages) {
|
||||
const c = pages[name].class;
|
||||
if (!byClass[c]) byClass[c] = [];
|
||||
byClass[c].push(pages[name]);
|
||||
}
|
||||
|
||||
// Sort each class: orphans first, then by incoming_links desc
|
||||
for (const c in byClass) {
|
||||
byClass[c].sort((a, b) => {
|
||||
if (a.orphan !== b.orphan) return a.orphan ? -1 : 1;
|
||||
return b.incoming_links - a.incoming_links;
|
||||
});
|
||||
}
|
||||
|
||||
// Render in order
|
||||
const main = document.getElementById('main');
|
||||
main.innerHTML = '';
|
||||
const orderedClasses = CLASS_ORDER.filter(c => byClass[c]).concat(
|
||||
Object.keys(byClass).filter(c => !CLASS_ORDER.includes(c))
|
||||
);
|
||||
|
||||
for (const c of orderedClasses) {
|
||||
const pages = byClass[c];
|
||||
const icon = ICONS[c] || '📄';
|
||||
const section = document.createElement('section');
|
||||
section.className = 'class-section';
|
||||
section.dataset.class = c;
|
||||
const orphCount = pages.filter(p => p.orphan).length;
|
||||
section.innerHTML = `
|
||||
<div class="class-title">
|
||||
<span class="icon">${icon}</span>
|
||||
<span>${c}</span>
|
||||
<span class="count">${pages.length} pages</span>
|
||||
${orphCount > 0 ? `<span class="orph-flag">${orphCount} orphelines</span>` : ''}
|
||||
</div>
|
||||
<div class="grid">
|
||||
${pages.map(p => `
|
||||
<a class="card${p.orphan ? ' orphan' : (p.incoming_links > 20 ? ' top' : '')}"
|
||||
href="${p.path}" target="_blank"
|
||||
data-search="${(p.name + ' ' + (p.title||'') + ' ' + c).toLowerCase()}">
|
||||
<div class="card-name" title="${p.name}">${p.title || p.name}</div>
|
||||
<div class="card-meta">
|
||||
<span class="meta-in" title="Liens entrants">${p.incoming_links}</span>
|
||||
<span class="meta-out" title="Liens sortants">${p.outgoing_links}</span>
|
||||
<span style="color:var(--txt-2)">${p.size_kb}kb</span>
|
||||
</div>
|
||||
</a>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
main.appendChild(section);
|
||||
}
|
||||
|
||||
// Search
|
||||
const search = document.getElementById('search');
|
||||
search.addEventListener('input', () => {
|
||||
const q = search.value.trim().toLowerCase();
|
||||
document.querySelectorAll('.card').forEach(card => {
|
||||
const hit = !q || card.dataset.search.includes(q);
|
||||
card.classList.toggle('hidden', !hit);
|
||||
});
|
||||
document.querySelectorAll('.class-section').forEach(s => {
|
||||
const visibleCards = s.querySelectorAll('.card:not(.hidden)');
|
||||
s.classList.toggle('hidden', q && visibleCards.length === 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
load();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user