Version mono-fichier : plus de dependances externes (Tailwind/Fonts/scipt.js separe)
This commit is contained in:
+407
-146
@@ -4,193 +4,454 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SysCmd — Command Reference</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; -webkit-font-smoothing: antialiased; line-height: 1.5; }
|
||||
.mono { font-family: 'JetBrains Mono', monospace; }
|
||||
.sidebar-link {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
padding: 4px 10px; border-radius: 6px;
|
||||
font-size: 0.8125rem; font-weight: 500;
|
||||
cursor: pointer; user-select: none; transition: all 0.12s;
|
||||
}
|
||||
.sidebar-link.active { background: #0f172a; color: white; }
|
||||
.sidebar-link:not(.active) { color: #475569; }
|
||||
.sidebar-link:not(.active):hover { background: #f1f5f9; color: #0f172a; }
|
||||
.sidebar-link-3 { padding-left: 48px; font-size: 0.75rem; }
|
||||
.sidebar-link-4 { padding-left: 64px; font-size: 0.6875rem; font-weight: 400; }
|
||||
.tree-toggle {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
width: 16px; height: 16px; flex-shrink: 0;
|
||||
transition: transform 0.15s; color: #94a3b8;
|
||||
}
|
||||
.tree-toggle.open { transform: rotate(90deg); }
|
||||
.tree-children { display: none; }
|
||||
.tree-children.open { display: block; }
|
||||
.cmd-row {
|
||||
display: grid;
|
||||
grid-template-columns: 190px 1fr;
|
||||
align-items: start; padding: 4px 12px;
|
||||
border-radius: 5px; font-size: 0.8125rem;
|
||||
transition: background 0.1s; gap: 8px;
|
||||
}
|
||||
.cmd-row:hover { background: #f1f5f9; }
|
||||
.cmd-row .cmd-desc { color: #475569; font-weight: 500; line-height: 1.4; }
|
||||
.cmd-row .cmd-text {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.75rem; color: #0f172a;
|
||||
cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
|
||||
line-height: 1.4; word-break: break-all;
|
||||
}
|
||||
.cmd-row .cmd-text:hover .copy-icon { opacity: 1; }
|
||||
.copy-icon { opacity: 0; width: 14px; height: 14px; flex-shrink: 0; color: #94a3b8; transition: opacity 0.12s; }
|
||||
.search-input {
|
||||
width: 100%; padding: 7px 12px 7px 34px;
|
||||
border-radius: 8px; font-size: 0.8125rem;
|
||||
outline: none; border: 1.5px solid #e2e8f0;
|
||||
background: white; transition: border-color 0.12s;
|
||||
}
|
||||
.search-input:focus { border-color: #0f172a; }
|
||||
.section-tab {
|
||||
padding: 4px 10px; border-radius: 5px;
|
||||
font-size: 0.6875rem; font-weight: 500;
|
||||
cursor: pointer; transition: all 0.12s;
|
||||
border: 1px solid #e2e8f0; color: #64748b; white-space: nowrap;
|
||||
}
|
||||
.section-tab.active { background: #0f172a; color: white; border-color: #0f172a; }
|
||||
.section-tab:hover:not(.active) { background: #f1f5f9; }
|
||||
.group-label {
|
||||
font-size: 0.625rem; font-weight: 700; text-transform: uppercase;
|
||||
letter-spacing: 0.05em; color: #94a3b8; padding: 8px 12px 4px;
|
||||
}
|
||||
.empty-state { padding: 40px 16px; max-width: 360px; margin: 0 auto; text-align: center; }
|
||||
.empty-state h3 { font-weight: 600; font-size: 0.9375rem; margin-bottom: 4px; color: #0f172a; }
|
||||
.empty-state p { font-size: 0.8125rem; color: #94a3b8; line-height: 1.5; }
|
||||
.dot-green { width: 6px; height: 6px; border-radius: 50%; background: #22c55e; flex-shrink: 0; }
|
||||
.dot-gray { width: 6px; height: 6px; border-radius: 50%; background: #cbd5e1; flex-shrink: 0; }
|
||||
.dot-orange { width: 6px; height: 6px; border-radius: 50%; background: #f59e0b; flex-shrink: 0; }
|
||||
.breadcrumb { font-size: 0.75rem; color: #94a3b8; display: flex; gap: 6px; align-items: center; margin-bottom: 2px; }
|
||||
.breadcrumb .current { color: #0f172a; font-weight: 500; }
|
||||
.os-card {
|
||||
border-radius: 10px; border: 1px solid #e2e8f0;
|
||||
background: white; cursor: pointer;
|
||||
transition: all 0.15s; padding: 16px;
|
||||
}
|
||||
.os-card:hover { border-color: #0f172a; box-shadow: 0 2px 12px rgba(0,0,0,0.08); }
|
||||
.os-card .icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||
.os-card .stat { font-size: 1.25rem; font-weight: 700; letter-spacing: -0.02em; }
|
||||
.os-card .sublabel { font-size: 0.6875rem; color: #94a3b8; }
|
||||
.placeholder-card { opacity: 0.6; }
|
||||
.placeholder-card:hover { opacity: 0.8; }
|
||||
.home-btn {
|
||||
padding: 5px 10px; border-radius: 6px; font-size: 0.75rem; font-weight: 500;
|
||||
cursor: pointer; transition: all 0.12s; color: #64748b;
|
||||
display: flex; align-items: center; gap: 5px;
|
||||
}
|
||||
.home-btn:hover { background: #f1f5f9; color: #0f172a; }
|
||||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;-webkit-font-smoothing:antialiased;line-height:1.5;background:#f8fafc;color:#0f172a}
|
||||
.flex{display:flex}.flex-col{flex-direction:column}.min-h-screen{min-height:100vh}.flex-1{flex:1}.overflow-y-auto{overflow-y:auto}
|
||||
.w-56{width:14rem}.border-r{border-right:1px solid #e2e8f0}.py-3{padding-top:0.75rem;padding-bottom:0.75rem}
|
||||
.px-3{padding-left:0.75rem;padding-right:0.75rem}.pb-3{padding-bottom:0.75rem}.mb-2{margin-bottom:0.5rem}
|
||||
.border-b{border-bottom:1px solid #f1f5f9}.bg-white{background:#fff}
|
||||
.items-center{align-items:center}.gap-2{gap:0.5rem}.gap-2\\.5{gap:0.625rem}
|
||||
.font-bold{font-weight:700}.text-sm{font-size:0.8125rem}
|
||||
.hidden{display:none}.lg\\:flex{display:flex}
|
||||
.sidebar-link{display:flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;font-size:0.8125rem;font-weight:500;cursor:pointer;user-select:none;transition:all 0.12s;color:#475569}
|
||||
.sidebar-link:hover{background:#f1f5f9;color:#0f172a}
|
||||
.sidebar-link.active{background:#0f172a;color:#fff}
|
||||
.sidebar-link-3{padding-left:48px;font-size:0.75rem}
|
||||
.sidebar-link-4{padding-left:64px;font-size:0.6875rem;font-weight:400}
|
||||
.tree-toggle{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex-shrink:0;transition:transform 0.15s;color:#94a3b8}
|
||||
.tree-toggle.open{transform:rotate(90deg)}
|
||||
.tree-children{display:none}.tree-children.open{display:block}
|
||||
.group-label{font-size:0.625rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:#94a3b8;padding:8px 12px 4px}
|
||||
.main{padding:1.5rem;max-width:64rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-3{margin-bottom:0.75rem}
|
||||
.mt-4{margin-top:1rem}
|
||||
.breadcrumb{font-size:0.75rem;color:#94a3b8;display:flex;gap:6px;align-items:center;margin-bottom:2px}
|
||||
.breadcrumb .current{color:#0f172a;font-weight:500}
|
||||
.text-xl{font-size:1.125rem}.font-bold{font-weight:700}
|
||||
.text-xs{font-size:0.6875rem}.text-sm{font-size:0.8125rem}
|
||||
.text-center{text-align:center}
|
||||
.text-\\[\\#64748b\\]{color:#64748b}.text-\\[\\#94a3b8\\]{color:#94a3b8}.text-\\[\\#0f172a\\]{color:#0f172a}
|
||||
.relative{position:relative}
|
||||
.search-input{width:100%;padding:7px 12px 7px 34px;border-radius:8px;font-size:0.8125rem;outline:none;border:1.5px solid #e2e8f0;background:#fff;transition:border-color 0.12s}
|
||||
.search-input:focus{border-color:#0f172a}
|
||||
.section-tab{padding:4px 10px;border-radius:5px;font-size:0.6875rem;font-weight:500;cursor:pointer;transition:all 0.12s;border:1px solid #e2e8f0;color:#64748b;white-space:nowrap}
|
||||
.section-tab.active{background:#0f172a;color:#fff;border-color:#0f172a}
|
||||
.section-tab:hover:not(.active){background:#f1f5f9}
|
||||
.cmd-row{display:grid;grid-template-columns:190px 1fr;align-items:start;padding:4px 12px;border-radius:5px;font-size:0.8125rem;transition:background 0.1s;gap:8px}
|
||||
.cmd-row:hover{background:#f1f5f9}
|
||||
.cmd-row .cmd-desc{color:#475569;font-weight:500;line-height:1.4}
|
||||
.cmd-row .cmd-text{font-family:'Cascadia Code','Fira Code','Consolas',monospace;font-size:0.75rem;color:#0f172a;cursor:pointer;display:inline-flex;align-items:center;gap:6px;line-height:1.4;word-break:break-all}
|
||||
.cmd-row .cmd-text:hover .copy-icon{opacity:1}
|
||||
.copy-icon{opacity:0;width:14px;height:14px;flex-shrink:0;color:#94a3b8;transition:opacity 0.12s}
|
||||
.bg-\\[\\#fafbfc\\]{background:#fafbfc}
|
||||
.dot-green{width:6px;height:6px;border-radius:50%;background:#22c55e;flex-shrink:0}
|
||||
.dot-gray{width:6px;height:6px;border-radius:50%;background:#cbd5e1;flex-shrink:0}
|
||||
.dot-orange{width:6px;height:6px;border-radius:50%;background:#f59e0b;flex-shrink:0}
|
||||
.flex-wrap{flex-wrap:wrap}.gap-1{gap:0.25rem}.gap-3{gap:0.75rem}
|
||||
.items-center{align-items:center}
|
||||
.justify-between{justify-content:space-between}
|
||||
.grid{display:grid}
|
||||
.grid-cols-1{grid-template-columns:repeat(1,1fr)}
|
||||
.os-card{border-radius:10px;border:1px solid #e2e8f0;background:#fff;cursor:pointer;transition:all 0.15s;padding:16px}
|
||||
.os-card:hover{border-color:#0f172a;box-shadow:0 2px 12px rgba(0,0,0,0.08)}
|
||||
.os-card .icon{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
|
||||
.os-card .sublabel{font-size:0.6875rem;color:#94a3b8}
|
||||
.os-card .stat-value{font-size:1.25rem;font-weight:700;letter-spacing:-0.02em}
|
||||
.placeholder-card{opacity:0.6}.placeholder-card:hover{opacity:0.8}
|
||||
.empty-state{padding:40px 16px;max-width:360px;margin:0 auto;text-align:center}
|
||||
.empty-state h3{font-weight:600;font-size:0.9375rem;margin-bottom:4px;color:#0f172a}
|
||||
.empty-state p{font-size:0.8125rem;color:#94a3b8;line-height:1.5}
|
||||
.stat-box{padding:12px;border:1px solid #e2e8f0;border-radius:10px;background:#fff;text-align:center}
|
||||
.stat-box .num{font-size:1.25rem;font-weight:700;color:#0f172a}
|
||||
.stat-box .lbl{font-size:0.6875rem;color:#94a3b8}
|
||||
.category-label{font-size:0.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:#94a3b8;margin-top:8px;margin-bottom:4px;grid-column:1/-1}
|
||||
.mt-auto{margin-top:auto}
|
||||
.pt-3{padding-top:0.75rem}
|
||||
.border-t{border-top:1px solid #f1f5f9}
|
||||
.rounded-xl{border-radius:12px}
|
||||
.overflow-hidden{overflow:hidden}
|
||||
.border{border:1px solid #e2e8f0}
|
||||
.divide-y>*+*{border-top:1px solid #f1f5f9}
|
||||
.p-8{padding:2rem}
|
||||
@media(min-width:640px){.sm\\:grid-cols-2{grid-template-columns:repeat(2,1fr)}}
|
||||
@media(min-width:1024px){.lg\\:flex{display:flex}.lg\\:grid-cols-3{grid-template-columns:repeat(3,1fr)}}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-[#f8fafc] text-[#0f172a]">
|
||||
|
||||
<body>
|
||||
<div class="flex min-h-screen">
|
||||
|
||||
<!-- SIDEBAR -->
|
||||
<aside class="hidden lg:flex flex-col w-56 border-r py-3 bg-white border-[#e2e8f0] overflow-y-auto">
|
||||
<div class="flex items-center gap-2.5 px-3 pb-3 mb-2 border-b border-[#f1f5f9]">
|
||||
<div class="w-7 h-7 bg-[#0f172a] rounded-lg flex items-center justify-center">
|
||||
<svg class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"/>
|
||||
</svg>
|
||||
<aside id="sidebar" class="w-56 border-r py-3 bg-white overflow-y-auto flex-col hidden lg:flex">
|
||||
<div class="flex items-center gap-2.5 px-3 pb-3 mb-2 border-b">
|
||||
<div style="width:28px;height:28px;background:#0f172a;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2.5"><path d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"/></svg>
|
||||
</div>
|
||||
<span class="font-bold text-sm">SysCmd</span>
|
||||
</div>
|
||||
|
||||
<div id="tree" class="flex-1 overflow-y-auto"></div>
|
||||
|
||||
<div class="pt-3 border-t border-[#f1f5f9] mt-auto">
|
||||
<div class="pt-3 border-t mt-auto">
|
||||
<div class="flex items-center gap-2 px-3 py-2">
|
||||
<div class="w-7 h-7 bg-[#e2e8f0] rounded-full flex items-center justify-center text-xs font-semibold text-[#64748b]">LK</div>
|
||||
<div class="text-xs"><div class="font-medium text-[#0f172a]">Laurent</div><div class="text-[#94a3b8]">sysadmin</div></div>
|
||||
<div style="width:28px;height:28px;background:#e2e8f0;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:0.75rem;font-weight:600;color:#64748b;flex-shrink:0">LK</div>
|
||||
<div style="font-size:0.75rem"><div style="font-weight:500;color:#0f172a">Laurent</div><div style="color:#94a3b8">sysadmin</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- MAIN -->
|
||||
<main class="flex-1 p-6 max-w-5xl" id="main-content">
|
||||
<main class="flex-1 main">
|
||||
|
||||
<!-- HEADER (visible on both views) -->
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="home-btn" id="home-btn" onclick="showHome()" style="display:none">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/></svg>
|
||||
Accueil
|
||||
</div>
|
||||
<!-- HEADER -->
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<div>
|
||||
<div class="breadcrumb" id="breadcrumb"></div>
|
||||
<h1 class="text-xl font-bold" id="os-title"></h1>
|
||||
<h1 class="text-xl font-bold" id="os-title">SysCmd</h1>
|
||||
<p class="text-xs text-[#64748b] mt-0.5" id="os-sub"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative">
|
||||
<svg class="absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-[#94a3b8]" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
|
||||
<input class="search-input" id="search" placeholder="Chercher une commande..." oninput="if(currentSection)filterCommands(this.value);else globalSearch(this.value)">
|
||||
<svg style="position:absolute;left:10px;top:50%;transform:translateY(-50%);width:14px;height:14px;color:#94a3b8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
|
||||
<input class="search-input" id="search" placeholder="Chercher une commande..." oninput="onSearch(this.value)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SECTION TABS (hidden on home) -->
|
||||
<div class="flex gap-1 flex-wrap mb-3" id="tabs" style="display:none"></div>
|
||||
<!-- TABS -->
|
||||
<div class="flex gap-1 flex-wrap mb-3" id="tabs"></div>
|
||||
|
||||
<!-- STATS BAR (hidden on home) -->
|
||||
<div class="flex gap-3 items-center mb-3 text-xs text-[#64748b]" id="stats-bar" style="display:none">
|
||||
<span id="shown">0</span>
|
||||
<span>commandes</span>
|
||||
<!-- STATS BAR -->
|
||||
<div class="flex gap-3 items-center mb-3 text-xs text-[#64748b]" id="stats-bar">
|
||||
<span id="shown">0</span> <span>commandes</span>
|
||||
<span>·</span>
|
||||
<span id="filter-info">Aucun filtre</span>
|
||||
</div>
|
||||
|
||||
<!-- COMMANDS LIST (hidden on home) -->
|
||||
<div class="bg-white border border-[#e2e8f0] rounded-xl overflow-hidden" id="cmds-container" style="display:none">
|
||||
<!-- COMMANDS -->
|
||||
<div class="bg-white border border-[#e2e8f0] rounded-xl overflow-hidden" id="cmds-container">
|
||||
<div id="cmds"></div>
|
||||
</div>
|
||||
|
||||
<!-- HOME CONTENT -->
|
||||
<!-- HOME -->
|
||||
<div id="home-content">
|
||||
|
||||
<!-- Hero -->
|
||||
<div class="mb-8 text-center">
|
||||
<h2 class="text-2xl font-bold mb-2">SysCmd</h2>
|
||||
<p class="text-sm text-[#64748b] max-w-xl mx-auto">
|
||||
Référence de commandes multi-plateforme. Cliquez sur un OS pour voir ses commandes.
|
||||
</p>
|
||||
<div class="mt-3 flex justify-center gap-2 text-xs text-[#94a3b8]">
|
||||
<span class="flex items-center gap-1"><span class="dot-green inline-block"></span> Données disponibles</span>
|
||||
<span class="flex items-center gap-1"><span class="dot-orange inline-block"></span> Catégorie</span>
|
||||
<span class="flex items-center gap-1"><span class="dot-gray inline-block"></span> À venir</span>
|
||||
<div class="text-center mb-6" style="margin-top:2rem">
|
||||
<h2 style="font-size:1.5rem;font-weight:700;margin-bottom:8px">SysCmd</h2>
|
||||
<p style="font-size:0.8125rem;color:#64748b;max-width:480px;margin:0 auto">Référence de commandes multi-plateforme. Cliquez sur un OS pour voir ses commandes.</p>
|
||||
<div style="margin-top:12px;display:flex;justify-content:center;gap:12px;font-size:0.6875rem;color:#94a3b8">
|
||||
<span class="flex items-center gap-1"><span class="dot-green" style="display:inline-block;vertical-align:middle"></span> Données disponibles</span>
|
||||
<span class="flex items-center gap-1"><span class="dot-orange" style="display:inline-block;vertical-align:middle"></span> Catégorie</span>
|
||||
<span class="flex items-center gap-1"><span class="dot-gray" style="display:inline-block;vertical-align:middle"></span> À venir</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Global search results -->
|
||||
<div id="global-search-results" class="mb-6" style="display:none">
|
||||
<div class="bg-white border border-[#e2e8f0] rounded-xl overflow-hidden">
|
||||
<div id="global-cmds"></div>
|
||||
</div>
|
||||
<div id="global-search-results" style="display:none;margin-bottom:1.5rem"></div>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 mb-6 text-center" id="stats-row"></div>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3" id="card-grid"></div>
|
||||
</div>
|
||||
|
||||
<!-- STATS ROW -->
|
||||
<div class="grid grid-cols-4 gap-3 mb-6 text-center" id="stats-row"></div>
|
||||
|
||||
<!-- CARD GRID avec catégories -->
|
||||
<div id="card-grid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3"></div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-center text-[0.6875rem] text-[#94a3b8]" id="footer-hint">
|
||||
Cliquez sur une commande pour la copier
|
||||
</div>
|
||||
<div class="mt-4 text-center text-xs text-[#94a3b8]" id="footer-hint">Cliquez sur un OS pour explorer ses commandes</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script src="script.js?v=2"></script>
|
||||
<script>
|
||||
"use strict";
|
||||
function t(fr,en){return{fr:fr,en:en}}
|
||||
|
||||
var currentNode=null,currentSection=null;
|
||||
|
||||
var TREE={id:'root',children:[
|
||||
{id:'os-cat',label:t('OS','OS'),children:[
|
||||
{id:'linux',label:t('Linux','Linux'),children:[
|
||||
{id:'ubuntu',label:t('Ubuntu','Ubuntu'),children:[
|
||||
{id:'ubuntu-2004',label:t('20.04','20.04'),osKey:'ubuntu',sectionIds:['sys','apt','users']},
|
||||
{id:'ubuntu-2204',label:t('22.04','22.04'),osKey:'ubuntu',sectionIds:['sys','apt','users']},
|
||||
{id:'ubuntu-2404',label:t('24.04','24.04'),osKey:'ubuntu',sectionIds:['sys','apt','users','systemd']}]},
|
||||
{id:'debian',label:t('Debian','Debian'),osKey:'debian',sectionIds:['sys','apt','users','systemd']},
|
||||
{id:'oracle',label:t('Oracle Linux','Oracle Linux'),osKey:'oracle',sectionIds:['oracle-dnf','oracle-spec','oracle-selinux','oracle-fw','systemd']},
|
||||
{id:'rhel',label:t('RHEL/CentOS','RHEL/CentOS')},{id:'fedora',label:t('Fedora','Fedora')}]},
|
||||
{id:'windows',label:t('Windows','Windows'),children:[
|
||||
{id:'win-client',label:t('Client','Client'),children:[
|
||||
{id:'win-xp',label:t('XP','XP')},{id:'win-10',label:t('10','10'),osKey:'windows',sectionIds:['win-sys','win-files','win-process','win-network']},
|
||||
{id:'win-11',label:t('11','11'),osKey:'windows',sectionIds:['win-sys','win-files','win-process','win-network']}]},
|
||||
{id:'win-server',label:t('Server','Server'),children:[
|
||||
{id:'win-2016',label:t('2016','2016'),osKey:'windows-server',sectionIds:['win-sys','win-files','win-process','win-network']},
|
||||
{id:'win-2019',label:t('2019','2019'),osKey:'windows-server',sectionIds:['win-sys','win-files','win-process','win-network']}]}]},
|
||||
{id:'solaris',label:t('Solaris/illumos','Solaris/illumos'),osKey:'solaris',sectionIds:['solaris-ips','solaris-smf','solaris-zfs','solaris-zones']},
|
||||
{id:'macos',label:t('macOS','macOS')}]},
|
||||
{id:'docker-cat',label:t('Docker','Docker'),children:[
|
||||
{id:'dc-compose',label:t('Compose','Compose')},{id:'dc-swarm',label:t('Swarm','Swarm')},{id:'dc-file',label:t('Dockerfile','Dockerfile')}]},
|
||||
{id:'other-cat',label:t('Other','Other'),children:[
|
||||
{id:'net',label:t('Reseau','Network'),children:[{id:'cisco',label:t('Cisco','Cisco')},{id:'tplink',label:t('TP-Link','TP-Link')}]},
|
||||
{id:'sql',label:t('SQL','SQL'),children:[{id:'mysql',label:t('MySQL/MariaDB','MySQL/MariaDB')},{id:'pg',label:t('PostgreSQL','PostgreSQL')}]},
|
||||
{id:'devops',label:t('DevOps','DevOps'),children:[{id:'ansible',label:t('Ansible','Ansible')},{id:'tf',label:t('Terraform','Terraform')},{id:'k8s',label:t('Kubernetes','Kubernetes')}]}]}]};
|
||||
|
||||
var SEC={};
|
||||
SEC.sys={label:t('systeme','system'),commands:[
|
||||
{d:t('Version noyau','Kernel version'),c:'uname -r'},
|
||||
{d:t('Version OS','OS version'),c:'lsb_release -a'},
|
||||
{d:t('Memoire dispo','Memory available'),c:'free -h'},
|
||||
{d:t("Nom d'hote",'Hostname'),c:'hostnamectl'},
|
||||
{d:t('Uptime','Uptime'),c:'uptime'},
|
||||
{d:t('Infos CPU','CPU info'),c:'lscpu'},
|
||||
{d:t('Date/heure','Date/time'),c:'timedatectl'}]};
|
||||
SEC.apt={label:t('APT','APT'),commands:[
|
||||
{d:t('Synchro depots','Sync repos'),c:'sudo apt update'},
|
||||
{d:t('Mise a jour','Full upgrade'),c:'sudo apt full-upgrade -y'},
|
||||
{d:t('Installer','Install'),c:'sudo apt install [package]'},
|
||||
{d:t('Purge','Purge'),c:'sudo apt purge [package]'},
|
||||
{d:t('Chercher','Search'),c:'apt search [keyword]'},
|
||||
{d:t('Paquets installes','Installed'),c:'apt list --installed'},
|
||||
{d:t('Fichiers fournis','Package files'),c:'dpkg -L [package]'}]};
|
||||
SEC.users={label:t('utilisateurs','users'),commands:[
|
||||
{d:t('Ajouter','Add user'),c:'sudo adduser [name]'},
|
||||
{d:t('Supprimer','Delete user'),c:'sudo deluser --remove-home [name]'},
|
||||
{d:t('Groupe sudo','Sudo group'),c:'sudo usermod -aG sudo [name]'},
|
||||
{d:t('Permissions','Permissions'),c:'chmod 755 [file]'},
|
||||
{d:t('Root','Root shell'),c:'sudo -i'}]};
|
||||
SEC.systemd={label:t('systemd','systemd'),commands:[
|
||||
{d:t('Start/Stop','Start/Stop'),c:'sudo systemctl start|stop [service]'},
|
||||
{d:t('Restart','Restart'),c:'sudo systemctl restart [service]'},
|
||||
{d:t('Enable','Enable'),c:'sudo systemctl enable [service]'},
|
||||
{d:t('Statut','Status'),c:'systemctl status [service]'},
|
||||
{d:t('Logs','Logs'),c:'journalctl -u [service] -n 50'},
|
||||
{d:t('Purger logs','Purge logs'),c:'sudo journalctl --vacuum-time=7d'}]};
|
||||
SEC['win-sys']={label:t('systeme','system'),commands:[
|
||||
{d:t('(CMD) Version','(CMD) Version'),c:'ver'},
|
||||
{d:t('(CMD) systeminfo','(CMD) systeminfo'),c:'systeminfo'},
|
||||
{d:t('(PS) Get-ComputerInfo','(PS) Get-ComputerInfo'),c:'Get-ComputerInfo'}]};
|
||||
SEC['win-files']={label:t('fichiers','files'),commands:[
|
||||
{d:t('(CMD) dir','(CMD) dir'),c:'dir /s'},
|
||||
{d:t('(CMD) rmdir','(CMD) rmdir'),c:'rmdir /s [folder]'},
|
||||
{d:t('(PS) Get-ChildItem','(PS) Get-ChildItem'),c:'Get-ChildItem -Recurse -Filter *.txt'}]};
|
||||
SEC['win-process']={label:t('processus','processes'),commands:[
|
||||
{d:t('(CMD) tasklist','(CMD) tasklist'),c:'tasklist'},
|
||||
{d:t('(CMD) taskkill','(CMD) taskkill'),c:'taskkill /IM notepad.exe /F'},
|
||||
{d:t('(PS) Get-Process','(PS) Get-Process'),c:'Get-Process'}]};
|
||||
SEC['win-network']={label:t('reseau','network'),commands:[
|
||||
{d:t('(CMD) ipconfig','(CMD) ipconfig'),c:'ipconfig /all'},
|
||||
{d:t('(CMD) netstat','(CMD) netstat'),c:'netstat -an | findstr LISTEN'},
|
||||
{d:t('(PS) Test-NetConnection','(PS) Test-NetConnection'),c:'Test-NetConnection [ip] -Port [port]'}]};
|
||||
SEC['oracle-dnf']={label:t('DNF','DNF'),commands:[
|
||||
{d:t('Synchro','Sync'),c:'sudo dnf check-update'},
|
||||
{d:t('Upgrade','Upgrade'),c:'sudo dnf upgrade -y'},
|
||||
{d:t('Install','Install'),c:'sudo dnf install [package]'},
|
||||
{d:t('Remove','Remove'),c:'sudo dnf remove [package]'}]};
|
||||
SEC['oracle-spec']={label:t('Oracle spec.','Oracle spec.'),commands:[
|
||||
{d:t('Ksplice status','Ksplice status'),c:'sudo uptrack-status'},
|
||||
{d:t('Ksplice upgrade','Ksplice upgrade'),c:'sudo uptrack-upgrade'},
|
||||
{d:t('Changer noyau','Switch kernel'),c:'sudo grubby --set-default /boot/vmlinuz-[ver]'}]};
|
||||
SEC['oracle-selinux']={label:t('SELinux','SELinux'),commands:[
|
||||
{d:t('Statut','Status'),c:'getenforce'},
|
||||
{d:t('Permissif','Permissive'),c:'sudo setenforce 0'},
|
||||
{d:t('Logs AVC','AVC logs'),c:'sudo ausearch -m avc -ts recent'}]};
|
||||
SEC['oracle-fw']={label:t('firewalld','firewalld'),commands:[
|
||||
{d:t('Status','Status'),c:'sudo firewall-cmd --state'},
|
||||
{d:t('Ouvrir port','Open port'),c:'sudo firewall-cmd --permanent --add-port=22/tcp'}]};
|
||||
SEC['solaris-ips']={label:t('IPS','IPS'),commands:[
|
||||
{d:t('Refresh','Refresh'),c:'sudo pkg refresh'},
|
||||
{d:t('Update','Update'),c:'sudo pkg update'},
|
||||
{d:t('Install','Install'),c:'sudo pkg install [package]'},
|
||||
{d:t('Remove','Remove'),c:'sudo pkg uninstall [package]'}]};
|
||||
SEC['solaris-smf']={label:t('SMF','SMF'),commands:[
|
||||
{d:t('Liste','List'),c:'svcs -a'},
|
||||
{d:t('Enable','Enable'),c:'sudo svcadm enable [service]'},
|
||||
{d:t('Disable','Disable'),c:'sudo svcadm disable [service]'},
|
||||
{d:t('Restart','Restart'),c:'sudo svcadm restart [service]'}]};
|
||||
SEC['solaris-zfs']={label:t('ZFS','ZFS'),commands:[
|
||||
{d:t('Pool status','Pool status'),c:'zpool status'},
|
||||
{d:t('Scrub','Scrub'),c:'sudo zpool scrub [pool]'},
|
||||
{d:t('Snapshot','Snapshot'),c:'sudo zfs snapshot [pool]/[ds]@[name]'},
|
||||
{d:t('Send/Receive','Send/Receive'),c:'zfs send [pool]/[ds]@snap | zfs receive [dest]'}]};
|
||||
SEC['solaris-zones']={label:t('Zones','Zones'),commands:[
|
||||
{d:t('Liste','List'),c:'zoneadm list -cv'},
|
||||
{d:t('Boot','Boot'),c:'sudo zoneadm -z [zone] boot'},
|
||||
{d:t('Halt','Halt'),c:'sudo zoneadm -z [zone] halt'},
|
||||
{d:t('Console','Console'),c:'sudo zlogin -C [zone]'}]};
|
||||
|
||||
// ALL COMMANDS for global search
|
||||
var ALL=[];
|
||||
(function(){var seen={};for(var k in SEC)if(SEC.hasOwnProperty(k))SEC[k].commands.forEach(function(x){var key=x.c;if(!seen[key]){seen[key]=true;ALL.push(x)}})})();
|
||||
|
||||
// HELPERS
|
||||
function findNode(tree,id){if(tree.id===id)return tree;for(var i=0;i<(tree.children||[]).length;i++){var f=findNode(tree.children[i],id);if(f)return f}return null}
|
||||
function collectLeaves(node,out){if(node.children){for(var i=0;i<node.children.length;i++)collectLeaves(node.children[i],out)}else{out.push(node)}return out}
|
||||
function countCmds(node){if(node.sectionIds){var n=0;for(var i=0;i<node.sectionIds.length;i++)if(SEC[node.sectionIds[i]])n+=SEC[node.sectionIds[i]].commands.length;return n}return 0}
|
||||
|
||||
function $(id){return document.getElementById(id)}
|
||||
|
||||
// RENDER TREE
|
||||
function renderTree(){var el=$('tree');el.innerHTML='';renderNode(el,TREE,0)}
|
||||
function renderNode(container,node,depth){
|
||||
var isBranch=node.children&&node.children.length>0,isVersion=!!node.sectionIds;
|
||||
var div=document.createElement('div');
|
||||
if(depth===0){
|
||||
var label=document.createElement('div');label.className='group-label';label.textContent='Categories';div.appendChild(label)
|
||||
}else{
|
||||
var row=document.createElement('div');
|
||||
var cls='sidebar-link';if(depth===2)cls+=' sidebar-link-3';if(depth===3)cls+=' sidebar-link-4';
|
||||
if(node===currentNode)cls+=' active';row.className=cls;
|
||||
if(isBranch){var tgl=document.createElement('span');tgl.className='tree-toggle open';
|
||||
tgl.innerHTML='<svg width="12" height="12" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 18l6-6-6-6"/></svg>';row.appendChild(tgl)
|
||||
}else{var sp=document.createElement('span');sp.style.cssText='width:16px;flex-shrink:0;display:inline-block';row.appendChild(sp)}
|
||||
var dot=document.createElement('span');
|
||||
if(isVersion||node._parent)dot.className='dot-green';else if(isBranch)dot.className='dot-orange';else dot.className='dot-gray';
|
||||
row.appendChild(dot);
|
||||
var lbl=document.createElement('span');lbl.textContent=node.label.fr;row.appendChild(lbl);
|
||||
var cnt=countCmds(node)||(node._parent&&node._parent.sectionIds?SEC[node._sectionId]?SEC[node._sectionId].commands.length:0:0);
|
||||
if(cnt>0){var b=document.createElement('span');b.className='ml-auto text-[0.625rem] text-[#94a3b8]';b.textContent=''+cnt;row.appendChild(b)}
|
||||
row.onclick=function(e){
|
||||
if(isBranch&&(e.target.closest('.tree-toggle')||e.target.closest('[data-toggle]'))){var tg=row.querySelector('.tree-toggle');if(tg){tg.classList.toggle('open');row.nextElementSibling.classList.toggle('open');e.stopPropagation()}return}
|
||||
if(isBranch)return;selectNode(node)
|
||||
};
|
||||
div.appendChild(row)
|
||||
}
|
||||
if(isBranch){
|
||||
var kids=document.createElement('div');kids.className='tree-children open';
|
||||
for(var i=0;i<node.children.length;i++){node.children[i]._parent=node;renderNode(kids,node.children[i],depth+1)}
|
||||
div.appendChild(kids)
|
||||
}
|
||||
if(isVersion&&node.sectionIds){
|
||||
var kids=document.createElement('div');kids.className='tree-children';
|
||||
if(node===currentNode||(currentNode&¤tNode._parent===node))kids.className='tree-children open';
|
||||
for(var j=0;j<node.sectionIds.length;j++){var sid=node.sectionIds[j],sec=SEC[sid];if(!sec)continue;
|
||||
var sn={id:node.id+'-'+sid,label:sec.label,_sectionId:sid,_parent:node};renderNode(kids,sn,depth+1)}
|
||||
div.appendChild(kids)
|
||||
}
|
||||
container.appendChild(div)
|
||||
}
|
||||
|
||||
// SELECT
|
||||
function selectNode(node){
|
||||
currentNode=node;currentSection=null;renderTree();
|
||||
$('search').value='';hideHome();$('breadcrumb').innerHTML='';
|
||||
var title=$('os-title'),sub=$('os-sub'),cmds=$('cmds');
|
||||
if(node._sectionId){var sec=SEC[node._sectionId];if(sec){title.textContent=(node._parent.label.fr||'')+' > '+sec.label.fr;sub.textContent=sec.commands.length+' commandes';showCmds(sec.commands)}return}
|
||||
if(node.sectionIds&&node.sectionIds.length>0){
|
||||
var sid=node.sectionIds[0],sec=SEC[sid];
|
||||
if(sec){title.textContent=node.label.fr;sub.textContent=node.sectionIds.length+' sections . '+countCmds(node)+' commandes';showCmds(sec.commands)}return
|
||||
}
|
||||
title.textContent=node.label.fr;sub.textContent='Aucune donnee';cmds.innerHTML='<div class="empty-state"><h3>'+node.label.fr+'</h3><p>Pas encore de commandes pour cet OS.</p></div>'
|
||||
}
|
||||
|
||||
function showHome(){
|
||||
currentNode=null;currentSection=null;renderTree();$('search').value='';
|
||||
$('home-content').style.display='block';$('tabs').style.display='none';$('stats-bar').style.display='none';
|
||||
$('cmds-container').style.display='none';$('breadcrumb').innerHTML='';
|
||||
$('os-title').textContent='SysCmd';$('os-sub').textContent='';$('footer-hint').textContent='Cliquez sur un OS pour explorer ses commandes';
|
||||
renderHome()
|
||||
}
|
||||
function hideHome(){$('home-content').style.display='none';$('tabs').style.display='flex';$('stats-bar').style.display='flex';$('cmds-container').style.display='block';$('footer-hint').textContent='Cliquez sur une commande pour la copier'}
|
||||
|
||||
// HOME
|
||||
function renderHome(){renderStats();renderCards()}
|
||||
function renderStats(){
|
||||
var totalCmds=ALL.length,totalSections=0;for(var k in SEC)if(SEC.hasOwnProperty(k))totalSections++;
|
||||
var leaves=collectLeaves(TREE,[]),totalOS=0;for(var i=0;i<leaves.length;i++)if(leaves[i].sectionIds)totalOS++;
|
||||
$('stats-row').innerHTML=
|
||||
'<div class="stat-box"><div class="num">'+totalCmds+'</div><div class="lbl">commandes</div></div>'+
|
||||
'<div class="stat-box"><div class="num">'+totalSections+'</div><div class="lbl">sections</div></div>'+
|
||||
'<div class="stat-box"><div class="num">'+totalOS+'</div><div class="lbl">OS renseignes</div></div>'+
|
||||
'<div class="stat-box"><div class="num" style="color:#94a3b8">'+(leaves.length-totalOS)+'</div><div class="lbl">placeholders</div></div>'
|
||||
}
|
||||
|
||||
var CARDS=[
|
||||
{id:'debian',label:'Debian',icon:'D',color:'#0f172a',desc:t('Distribution stable','Stable distribution'),cat:'os'},
|
||||
{id:'ubuntu',label:'Ubuntu',icon:'U',color:'#dc2626',desc:t('Base Debian avec LTS','Debian-based LTS'),cat:'os',group:true},
|
||||
{id:'oracle',label:'Oracle Linux',icon:'O',color:'#b9141e',desc:t('Linux UEK+SELinux','Linux UEK+SELinux'),cat:'os'},
|
||||
{id:'windows',label:'Windows',icon:'W',color:'#0078d4',desc:t('CMD+PS client/server','CMD+PS client/server'),cat:'os',group:true},
|
||||
{id:'solaris',label:'Solaris',icon:'S',color:'#b46400',desc:t('Solaris+ZFS+DTrace','Solaris+ZFS+DTrace'),cat:'os'},
|
||||
{id:'rhel',label:'RHEL/CentOS',icon:'R',color:'#94a3b8',desc:t('Enterprise Linux','Enterprise Linux'),cat:'os',ph:true},
|
||||
{id:'fedora',label:'Fedora',icon:'F',color:'#94a3b8',desc:t('RHEL-based','RHEL-based'),cat:'os',ph:true},
|
||||
{id:'macos',label:'macOS',icon:'M',color:'#94a3b8',desc:t('macOS','macOS'),cat:'os',ph:true},
|
||||
{id:'dc-compose',label:'Docker Compose',icon:'D',color:'#0ea5e9',desc:t('Multi-conteneurs','Multi-container'),cat:'docker',ph:true},
|
||||
{id:'dc-swarm',label:'Docker Swarm',icon:'S',color:'#0ea5e9',desc:t('Cluster natif','Native cluster'),cat:'docker',ph:true},
|
||||
{id:'dc-file',label:'Dockerfile',icon:'F',color:'#0ea5e9',desc:t('Build instructions','Build instructions'),cat:'docker',ph:true},
|
||||
{id:'cisco',label:'Cisco IOS',icon:'C',color:'#8b5cf6',desc:t('Reseau Cisco','Cisco networking'),cat:'other',ph:true},
|
||||
{id:'mysql',label:'MySQL/MariaDB',icon:'S',color:'#8b5cf6',desc:t('Bases SQL','SQL databases'),cat:'other',ph:true},
|
||||
{id:'pg',label:'PostgreSQL',icon:'P',color:'#8b5cf6',desc:t('Base avancee','Advanced DB'),cat:'other',ph:true},
|
||||
{id:'ansible',label:'Ansible',icon:'A',color:'#8b5cf6',desc:t('Automatisation IT','IT automation'),cat:'other',ph:true},
|
||||
{id:'k8s',label:'Kubernetes',icon:'K',color:'#8b5cf6',desc:t('Orchestration','Orchestration'),cat:'other',ph:true}];
|
||||
|
||||
function renderCards(){
|
||||
var cats={os:{label:t('Systemes d exploitation','Operating Systems'),html:''},docker:{label:t('Docker/Conteneurs','Docker/Containers'),html:''},other:{label:t('Reseau, BDD, DevOps','Network, DB, DevOps'),html:''}};
|
||||
CARDS.forEach(function(card){
|
||||
var n=findNode(TREE,card.id),cnt=n?countCmds(n):0,ph=card.ph&&cnt===0;
|
||||
if(!cats[card.cat])cats[card.cat]={label:card.cat,html:''};
|
||||
var h='<div class="os-card'+(ph?' placeholder-card':'')+'">'+
|
||||
'<div class="flex items-start gap-3 mb-3">'+
|
||||
'<div class="icon" style="background:'+(ph?'#e2e8f0':card.color)+(ph?';color:#94a3b8':';color:#fff')+'"><span style="font-weight:700;font-size:0.8125rem">'+card.icon+'</span></div>'+
|
||||
'<div class="flex-1" style="min-width:0"><div style="font-weight:600;font-size:0.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'+(card.group?card.label+' >':card.label)+'</div>'+
|
||||
'<div class="sublabel">'+card.desc.fr+'</div></div></div>'+
|
||||
'<div class="flex items-center gap-2 text-xs">'+(cnt>0?'<span style="font-weight:600;color:#0f172a">'+cnt+'</span><span style="color:#94a3b8">commandes</span>':'<span style="color:#cbd5e1">'+(ph?'A venir':'via sidebar')+'</span>')+'</div></div>';
|
||||
cats[card.cat].html+=h
|
||||
});
|
||||
var html='';
|
||||
Object.keys(cats).forEach(function(k){html+='<div class="category-label">'+cats[k].label.fr+'</div>'+cats[k].html});
|
||||
$('card-grid').innerHTML=html;
|
||||
|
||||
// Click handlers
|
||||
$('card-grid').querySelectorAll('.os-card').forEach(function(el,i){
|
||||
var card=CARDS[i%CARDS.length]; // simplified
|
||||
});
|
||||
// Re-bind properly
|
||||
var idx=0;
|
||||
$('card-grid').querySelectorAll('.os-card').forEach(function(el){
|
||||
var card=CARDS[idx++];
|
||||
if(!card)return;
|
||||
el.onclick=function(){
|
||||
var n=findNode(TREE,card.id);
|
||||
if(card.group){if(n&&n.children&&n.children.length>0)selectNode(n.children[0])}
|
||||
else if(n)selectNode(n)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function showCmds(commands){
|
||||
var el=$('cmds'),sv=$('search').value.trim().toLowerCase();
|
||||
var cmds=sv?commands.filter(function(x){return x.d.fr.toLowerCase().indexOf(sv)!==-1||x.d.en.toLowerCase().indexOf(sv)!==-1||x.c.toLowerCase().indexOf(sv)!==-1}):commands;
|
||||
$('shown').textContent=''+cmds.length;
|
||||
if(cmds.length===0){el.innerHTML='<div class="p-8 text-center text-sm" style="color:#94a3b8">Aucune commande trouvee</div>';return}
|
||||
el.innerHTML='';
|
||||
cmds.forEach(function(x,i){
|
||||
var row=document.createElement('div');row.className='cmd-row'+(i%2===0?' bg-[#fafbfc]':'');
|
||||
var cmdSafe=x.c.replace(/"/g,'"');
|
||||
row.innerHTML='<div class="cmd-desc">'+x.d.fr+'</div><div class="cmd-text"><span class="copy-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg></span><span>'+x.c+'</span></div>';
|
||||
row.querySelector('.cmd-text').onclick=function(){
|
||||
navigator.clipboard.writeText(x.c).then(function(){
|
||||
var icon=row.querySelector('.copy-icon');
|
||||
icon.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2.5" width="14" height="14"><polyline points="20 6 9 17 4 12"/></svg>';
|
||||
setTimeout(function(){icon.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>'},1200)
|
||||
})
|
||||
};
|
||||
el.appendChild(row)
|
||||
})
|
||||
}
|
||||
|
||||
function onSearch(val){
|
||||
var fi=$('filter-info');
|
||||
fi.textContent=val.trim()?'Filtre: "'+val+'"':'Aucun filtre';
|
||||
if(currentNode&¤tNode._sectionId){showCmds(SEC[currentNode._sectionId].commands);return}
|
||||
if(currentNode&¤tNode.sectionIds&¤tNode.sectionIds.length>0){showCmds(SEC[currentNode.sectionIds[0]].commands);return}
|
||||
// Global search on home
|
||||
if(!currentNode&&val.trim()){
|
||||
var results=ALL.filter(function(x){return x.d.fr.toLowerCase().indexOf(val.trim().toLowerCase())!==-1||x.d.en.toLowerCase().indexOf(val.trim().toLowerCase())!==-1||x.c.toLowerCase().indexOf(val.trim().toLowerCase())!==-1});
|
||||
var el=$('global-search-results');el.style.display='block';
|
||||
el.innerHTML='<div class="bg-white border border-[#e2e8f0] rounded-xl overflow-hidden">';
|
||||
if(results.length===0){el.innerHTML+='<div class="p-8 text-center text-sm" style="color:#94a3b8">Aucun resultat</div>'}
|
||||
else{
|
||||
el.firstChild.innerHTML='<div style="padding:8px 12px;font-size:0.6875rem;color:#94a3b8;border-bottom:1px solid #f1f5f9">'+results.length+' resultat(s)</div><div id="gcmds"></div>';
|
||||
var g=$('gcmds')||el.querySelector('#gcmds');
|
||||
results.forEach(function(x,i){
|
||||
var row=document.createElement('div');row.className='cmd-row'+(i%2===0?' bg-[#fafbfc]':'');
|
||||
row.innerHTML='<div class="cmd-desc">'+x.d.fr+'</div><div class="cmd-text"><span class="copy-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg></span><span>'+x.c+'</span></div>';
|
||||
row.querySelector('.cmd-text').onclick=function(){navigator.clipboard.writeText(x.c)};
|
||||
g.appendChild(row)
|
||||
})
|
||||
}
|
||||
el.innerHTML+='</div>';$('card-grid').style.display='none';$('stats-row').style.display='none'
|
||||
}else if(!currentNode){$('global-search-results').style.display='none';$('card-grid').style.display='grid';$('stats-row').style.display='grid'}
|
||||
}
|
||||
|
||||
renderTree();
|
||||
showHome();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,591 +0,0 @@
|
||||
/* SYSCMD — arbre avec sections en sous-niveaux + page d'accueil */
|
||||
function t(fr, en) { return { fr: fr, en: en }; }
|
||||
|
||||
let currentNode = null;
|
||||
let currentSection = null;
|
||||
|
||||
const TREE = {
|
||||
id: 'root',
|
||||
children: [
|
||||
{
|
||||
id: 'os-cat', label: t('OS', 'OS'), children: [
|
||||
{ id: 'linux', label: t('Linux', 'Linux'), children: [
|
||||
{ id: 'ubuntu', label: t('Ubuntu', 'Ubuntu'), children: [
|
||||
{ id: 'ubuntu-2004', label: t('20.04', '20.04'), osKey: 'ubuntu', sectionIds: ['sys','apt','users'] },
|
||||
{ id: 'ubuntu-2204', label: t('22.04', '22.04'), osKey: 'ubuntu', sectionIds: ['sys','apt','users'] },
|
||||
{ id: 'ubuntu-2404', label: t('24.04', '24.04'), osKey: 'ubuntu', sectionIds: ['sys','apt','users','systemd'] },
|
||||
]},
|
||||
{ id: 'debian', label: t('Debian', 'Debian'), osKey: 'debian', sectionIds: ['sys','apt','users','systemd'] },
|
||||
{ id: 'oracle', label: t('Oracle Linux', 'Oracle Linux'), osKey: 'oracle', sectionIds: ['oracle-dnf','oracle-spec','oracle-selinux','oracle-fw','systemd'] },
|
||||
{ id: 'rhel', label: t('RHEL / CentOS', 'RHEL / CentOS') },
|
||||
{ id: 'fedora', label: t('Fedora', 'Fedora') },
|
||||
]},
|
||||
{ id: 'windows', label: t('Windows', 'Windows'), children: [
|
||||
{ id: 'win-client', label: t('Client', 'Client'), children: [
|
||||
{ id: 'win-xp', label: t('XP', 'XP') },
|
||||
{ id: 'win-10', label: t('10', '10'), osKey: 'windows', sectionIds: ['win-sys','win-files','win-process','win-network'] },
|
||||
{ id: 'win-11', label: t('11', '11'), osKey: 'windows', sectionIds: ['win-sys','win-files','win-process','win-network'] },
|
||||
]},
|
||||
{ id: 'win-server', label: t('Server', 'Server'), children: [
|
||||
{ id: 'win-2016', label: t('2016', '2016'), osKey: 'windows-server', sectionIds: ['win-sys','win-files','win-process','win-network'] },
|
||||
{ id: 'win-2019', label: t('2019', '2019'), osKey: 'windows-server', sectionIds: ['win-sys','win-files','win-process','win-network'] },
|
||||
]},
|
||||
]},
|
||||
{ id: 'solaris', label: t('Solaris / illumos', 'Solaris / illumos'), osKey: 'solaris', sectionIds: ['solaris-ips','solaris-smf','solaris-zfs','solaris-zones'] },
|
||||
{ id: 'macos', label: t('macOS', 'macOS') },
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'docker-cat', label: t('Docker', 'Docker'), children: [
|
||||
{ id: 'docker-compose', label: t('Compose', 'Compose') },
|
||||
{ id: 'docker-swarm', label: t('Swarm', 'Swarm') },
|
||||
{ id: 'dockerfile', label: t('Dockerfile', 'Dockerfile') },
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'other-cat', label: t('Other', 'Other'), children: [
|
||||
{ id: 'network', label: t('Réseau', 'Network'), children: [
|
||||
{ id: 'cisco', label: t('Cisco IOS', 'Cisco IOS') },
|
||||
{ id: 'tplink', label: t('TP-Link', 'TP-Link') },
|
||||
]},
|
||||
{ id: 'sql', label: t('SQL', 'SQL'), children: [
|
||||
{ id: 'mysql', label: t('MySQL / MariaDB', 'MySQL / MariaDB') },
|
||||
{ id: 'postgresql', label: t('PostgreSQL', 'PostgreSQL') },
|
||||
]},
|
||||
{ id: 'tools', label: t('DevOps', 'DevOps'), children: [
|
||||
{ id: 'ansible', label: t('Ansible', 'Ansible') },
|
||||
{ id: 'terraform', label: t('Terraform', 'Terraform') },
|
||||
{ id: 'kubernetes', label: t('Kubernetes', 'Kubernetes') },
|
||||
]},
|
||||
]
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
const SEC = {};
|
||||
|
||||
SEC.sys = { label: t('système', 'system'), commands: [
|
||||
{ d: t('Version du noyau', 'Kernel version'), c: 'uname -r' },
|
||||
{ d: t('Version OS', 'OS version'), c: 'lsb_release -a' },
|
||||
{ d: t('Mémoire dispo', 'Memory available'), c: 'free -h' },
|
||||
{ d: t("Nom d'hôte", 'Hostname'), c: 'hostnamectl' },
|
||||
{ d: t('Uptime', 'Uptime'), c: 'uptime' },
|
||||
{ d: t('Infos CPU', 'CPU info'), c: 'lscpu' },
|
||||
{ d: t('Date / heure', 'Date / time'), c: 'timedatectl' },
|
||||
]};
|
||||
|
||||
SEC.apt = { label: t('APT', 'APT'), commands: [
|
||||
{ d: t('Synchro dépôts', 'Sync repos'), c: 'sudo apt update' },
|
||||
{ d: t('Mise à jour', 'Full upgrade'), c: 'sudo apt full-upgrade -y' },
|
||||
{ d: t('Installer', 'Install'), c: 'sudo apt install [package]' },
|
||||
{ d: t('Purge', 'Purge'), c: 'sudo apt purge [package]' },
|
||||
{ d: t('Chercher', 'Search'), c: 'apt search [keyword]' },
|
||||
{ d: t('Paquets installés', 'Installed'), c: 'apt list --installed' },
|
||||
{ d: t('Fichiers fournis', 'Package files'), c: 'dpkg -L [package]' },
|
||||
]};
|
||||
|
||||
SEC.users = { label: t('utilisateurs', 'users'), commands: [
|
||||
{ d: t('Ajouter', 'Add user'), c: 'sudo adduser [name]' },
|
||||
{ d: t('Supprimer', 'Delete user'), c: 'sudo deluser --remove-home [name]' },
|
||||
{ d: t('Groupe sudo', 'Sudo group'), c: 'sudo usermod -aG sudo [name]' },
|
||||
{ d: t('Permissions', 'Permissions'), c: 'chmod 755 [file]' },
|
||||
{ d: t('Root', 'Root shell'), c: 'sudo -i' },
|
||||
]};
|
||||
|
||||
SEC.systemd = { label: t('systemd', 'systemd'), commands: [
|
||||
{ d: t('Start/Stop', 'Start/Stop'), c: 'sudo systemctl start|stop [service]' },
|
||||
{ d: t('Restart', 'Restart'), c: 'sudo systemctl restart [service]' },
|
||||
{ d: t('Enable', 'Enable'), c: 'sudo systemctl enable [service]' },
|
||||
{ d: t('Statut', 'Status'), c: 'systemctl status [service]' },
|
||||
{ d: t('Logs', 'Logs'), c: 'journalctl -u [service] -n 50' },
|
||||
{ d: t('Purger logs', 'Purge logs'), c: 'sudo journalctl --vacuum-time=7d' },
|
||||
]};
|
||||
|
||||
SEC['win-sys'] = { label: t('système', 'system'), commands: [
|
||||
{ d: t('(CMD) Version', '(CMD) Version'), c: 'ver' },
|
||||
{ d: t('(CMD) systeminfo', '(CMD) systeminfo'), c: 'systeminfo' },
|
||||
{ d: t('(PS) Get-ComputerInfo', '(PS) Get-ComputerInfo'), c: 'Get-ComputerInfo' },
|
||||
]};
|
||||
|
||||
SEC['win-files'] = { label: t('fichiers', 'files'), commands: [
|
||||
{ d: t('(CMD) dir', '(CMD) dir'), c: 'dir /s' },
|
||||
{ d: t('(CMD) rmdir', '(CMD) rmdir'), c: 'rmdir /s [folder]' },
|
||||
{ d: t('(PS) Get-ChildItem', '(PS) Get-ChildItem'), c: 'Get-ChildItem -Recurse -Filter *.txt' },
|
||||
]};
|
||||
|
||||
SEC['win-process'] = { label: t('processus', 'processes'), commands: [
|
||||
{ d: t('(CMD) tasklist', '(CMD) tasklist'), c: 'tasklist' },
|
||||
{ d: t('(CMD) taskkill', '(CMD) taskkill'), c: 'taskkill /IM notepad.exe /F' },
|
||||
{ d: t('(PS) Get-Process', '(PS) Get-Process'), c: 'Get-Process' },
|
||||
]};
|
||||
|
||||
SEC['win-network'] = { label: t('réseau', 'network'), commands: [
|
||||
{ d: t('(CMD) ipconfig', '(CMD) ipconfig'), c: 'ipconfig /all' },
|
||||
{ d: t('(CMD) netstat', '(CMD) netstat'), c: 'netstat -an | findstr LISTEN' },
|
||||
{ d: t('(PS) Test-NetConnection', '(PS) Test-NetConnection'), c: 'Test-NetConnection [ip] -Port [port]' },
|
||||
]};
|
||||
|
||||
SEC['oracle-dnf'] = { label: t('DNF', 'DNF'), commands: [
|
||||
{ d: t('Synchro', 'Sync'), c: 'sudo dnf check-update' },
|
||||
{ d: t('Upgrade', 'Upgrade'), c: 'sudo dnf upgrade -y' },
|
||||
{ d: t('Install', 'Install'), c: 'sudo dnf install [package]' },
|
||||
{ d: t('Remove', 'Remove'), c: 'sudo dnf remove [package]' },
|
||||
]};
|
||||
|
||||
SEC['oracle-spec'] = { label: t('Oracle spec.', 'Oracle spec.'), commands: [
|
||||
{ d: t('Ksplice status', 'Ksplice status'), c: 'sudo uptrack-status' },
|
||||
{ d: t('Ksplice upgrade', 'Ksplice upgrade'), c: 'sudo uptrack-upgrade' },
|
||||
{ d: t('Changer noyau', 'Switch kernel'), c: 'sudo grubby --set-default /boot/vmlinuz-[ver]' },
|
||||
]};
|
||||
|
||||
SEC['oracle-selinux'] = { label: t('SELinux', 'SELinux'), commands: [
|
||||
{ d: t('Statut', 'Status'), c: 'getenforce' },
|
||||
{ d: t('Permissif', 'Permissive'), c: 'sudo setenforce 0' },
|
||||
{ d: t('Logs AVC', 'AVC logs'), c: 'sudo ausearch -m avc -ts recent' },
|
||||
]};
|
||||
|
||||
SEC['oracle-fw'] = { label: t('firewalld', 'firewalld'), commands: [
|
||||
{ d: t('Status', 'Status'), c: 'sudo firewall-cmd --state' },
|
||||
{ d: t('Ouvrir port', 'Open port'), c: 'sudo firewall-cmd --permanent --add-port=22/tcp' },
|
||||
]};
|
||||
|
||||
SEC['solaris-ips'] = { label: t('IPS', 'IPS'), commands: [
|
||||
{ d: t('Refresh', 'Refresh'), c: 'sudo pkg refresh' },
|
||||
{ d: t('Update', 'Update'), c: 'sudo pkg update' },
|
||||
{ d: t('Install', 'Install'), c: 'sudo pkg install [package]' },
|
||||
{ d: t('Remove', 'Remove'), c: 'sudo pkg uninstall [package]' },
|
||||
]};
|
||||
|
||||
SEC['solaris-smf'] = { label: t('SMF', 'SMF'), commands: [
|
||||
{ d: t('Liste', 'List'), c: 'svcs -a' },
|
||||
{ d: t('Enable', 'Enable'), c: 'sudo svcadm enable [service]' },
|
||||
{ d: t('Disable', 'Disable'), c: 'sudo svcadm disable [service]' },
|
||||
{ d: t('Restart', 'Restart'), c: 'sudo svcadm restart [service]' },
|
||||
]};
|
||||
|
||||
SEC['solaris-zfs'] = { label: t('ZFS', 'ZFS'), commands: [
|
||||
{ d: t('Pool status', 'Pool status'), c: 'zpool status' },
|
||||
{ d: t('Scrub', 'Scrub'), c: 'sudo zpool scrub [pool]' },
|
||||
{ d: t('Snapshot', 'Snapshot'), c: 'sudo zfs snapshot [pool]/[ds]@[name]' },
|
||||
{ d: t('Send/Receive', 'Send/Receive'), c: 'zfs send [pool]/[ds]@snap | zfs receive [dest]' },
|
||||
]};
|
||||
|
||||
SEC['solaris-zones'] = { label: t('Zones', 'Zones'), commands: [
|
||||
{ d: t('Liste', 'List'), c: 'zoneadm list -cv' },
|
||||
{ d: t('Boot', 'Boot'), c: 'sudo zoneadm -z [zone] boot' },
|
||||
{ d: t('Halt', 'Halt'), c: 'sudo zoneadm -z [zone] halt' },
|
||||
{ d: t('Console', 'Console'), c: 'sudo zlogin -C [zone]' },
|
||||
]};
|
||||
|
||||
// ── COLLECT ALL COMMANDS (for global search) ──
|
||||
var ALL_COMMANDS = [];
|
||||
(function() {
|
||||
var seen = {};
|
||||
for (var k in SEC) {
|
||||
if (SEC.hasOwnProperty(k)) {
|
||||
SEC[k].commands.forEach(function(cmd) {
|
||||
var key = cmd.c;
|
||||
if (!seen[key]) { seen[key] = true; ALL_COMMANDS.push(cmd); }
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// ── HELPERS ──
|
||||
function findNode(tree, id) {
|
||||
if (tree.id === id) return tree;
|
||||
for (var i = 0; i < (tree.children || []).length; i++) {
|
||||
var f = findNode(tree.children[i], id);
|
||||
if (f) return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function collectLeafNodes(node, out) {
|
||||
if (node.children) {
|
||||
for (var i = 0; i < node.children.length; i++) collectLeafNodes(node.children[i], out);
|
||||
} else {
|
||||
out.push(node);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function countNodeCmds(node) {
|
||||
if (node.sectionIds) {
|
||||
var n = 0;
|
||||
for (var i = 0; i < node.sectionIds.length; i++) {
|
||||
if (SEC[node.sectionIds[i]]) n += SEC[node.sectionIds[i]].commands.length;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ── RENDER TREE ──
|
||||
function renderTree() {
|
||||
var el = document.getElementById('tree');
|
||||
el.innerHTML = '';
|
||||
renderNode(el, TREE, 0);
|
||||
}
|
||||
|
||||
function renderNode(container, node, depth) {
|
||||
var isBranch = node.children && node.children.length > 0;
|
||||
var isVersion = !!node.sectionIds;
|
||||
var div = document.createElement('div');
|
||||
|
||||
if (depth === 0) {
|
||||
var label = document.createElement('div');
|
||||
label.className = 'group-label';
|
||||
label.textContent = node.label.fr;
|
||||
div.appendChild(label);
|
||||
} else {
|
||||
var row = document.createElement('div');
|
||||
var cls = 'sidebar-link';
|
||||
if (depth === 2) cls += ' sidebar-link-3';
|
||||
if (depth === 3) cls += ' sidebar-link-4';
|
||||
if (node === currentNode) cls += ' active';
|
||||
row.className = cls;
|
||||
|
||||
if (isBranch) {
|
||||
var tgl = document.createElement('span');
|
||||
tgl.className = 'tree-toggle open';
|
||||
tgl.innerHTML = '<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 18l6-6-6-6"/></svg>';
|
||||
row.appendChild(tgl);
|
||||
} else {
|
||||
var sp = document.createElement('span');
|
||||
sp.style.cssText = 'width:16px;flex-shrink:0;display:inline-block';
|
||||
row.appendChild(sp);
|
||||
}
|
||||
|
||||
var dot = document.createElement('span');
|
||||
if (isVersion || node._parent) dot.className = 'dot-green';
|
||||
else if (isBranch) dot.className = 'dot-orange';
|
||||
else dot.className = 'dot-gray';
|
||||
row.appendChild(dot);
|
||||
|
||||
var lbl = document.createElement('span');
|
||||
lbl.textContent = node.label.fr;
|
||||
row.appendChild(lbl);
|
||||
|
||||
var cnt = countNodeCmds(node) || (node._parent && node._parent.sectionIds ? SEC[node._sectionId] ? SEC[node._sectionId].commands.length : 0 : 0);
|
||||
if (cnt > 0) {
|
||||
var b = document.createElement('span');
|
||||
b.className = 'ml-auto text-[0.625rem] text-[#94a3b8]';
|
||||
b.textContent = '' + cnt;
|
||||
row.appendChild(b);
|
||||
}
|
||||
|
||||
row.onclick = function(e) {
|
||||
if (isBranch && (e.target.closest('.tree-toggle') || e.target.closest('[data-toggle]'))) {
|
||||
var tg = row.querySelector('.tree-toggle');
|
||||
if (tg) { tg.classList.toggle('open'); row.nextElementSibling.classList.toggle('open'); e.stopPropagation(); }
|
||||
return;
|
||||
}
|
||||
if (isBranch) return; // only leaf nodes select
|
||||
selectNode(node);
|
||||
};
|
||||
|
||||
div.appendChild(row);
|
||||
}
|
||||
|
||||
if (isBranch) {
|
||||
var kids = document.createElement('div');
|
||||
kids.className = 'tree-children open';
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
node.children[i]._parent = node;
|
||||
renderNode(kids, node.children[i], depth + 1);
|
||||
}
|
||||
div.appendChild(kids);
|
||||
}
|
||||
|
||||
if (isVersion && node.sectionIds) {
|
||||
var kids = document.createElement('div');
|
||||
kids.className = 'tree-children';
|
||||
if (node === currentNode || (currentNode && currentNode._parent === node)) {
|
||||
kids.className = 'tree-children open';
|
||||
}
|
||||
for (var j = 0; j < node.sectionIds.length; j++) {
|
||||
var sid = node.sectionIds[j];
|
||||
var sec = SEC[sid];
|
||||
if (!sec) continue;
|
||||
var snode = { id: node.id + '-' + sid, label: sec.label, _sectionId: sid, _parent: node };
|
||||
renderNode(kids, snode, depth + 1);
|
||||
}
|
||||
div.appendChild(kids);
|
||||
}
|
||||
|
||||
container.appendChild(div);
|
||||
}
|
||||
|
||||
// ── SELECT NODE ──
|
||||
function selectNode(node) {
|
||||
currentNode = node;
|
||||
currentSection = null;
|
||||
renderTree();
|
||||
|
||||
document.getElementById('search').value = '';
|
||||
hideHome();
|
||||
document.getElementById('home-btn').style.display = 'flex';
|
||||
|
||||
var titleEl = document.getElementById('os-title');
|
||||
var subEl = document.getElementById('os-sub');
|
||||
var cmdsEl = document.getElementById('cmds');
|
||||
|
||||
if (node._sectionId) {
|
||||
var sec = SEC[node._sectionId];
|
||||
if (sec) {
|
||||
titleEl.textContent = node._parent.label.fr + ' > ' + sec.label.fr;
|
||||
subEl.textContent = sec.commands.length + ' commandes';
|
||||
showCmds(sec.commands);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.sectionIds && node.sectionIds.length > 0) {
|
||||
var sid = node.sectionIds[0];
|
||||
var sec = SEC[sid];
|
||||
if (sec) {
|
||||
titleEl.textContent = node.label.fr;
|
||||
subEl.textContent = node.sectionIds.length + ' sections · ' + countNodeCmds(node) + ' commandes';
|
||||
showCmds(sec.commands);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
titleEl.textContent = node.label.fr;
|
||||
subEl.textContent = 'Aucune donnée';
|
||||
cmdsEl.innerHTML = '<div class="empty-state"><h3>' + node.label.fr + '</h3><p>Pas encore de commandes pour cet OS.</p></div>';
|
||||
}
|
||||
|
||||
// ── SHOW/HIDE HOME ──
|
||||
function showHome() {
|
||||
currentSection = null;
|
||||
currentNode = null;
|
||||
renderTree();
|
||||
document.getElementById('search').value = '';
|
||||
document.getElementById('filter-info').textContent = 'Aucun filtre';
|
||||
document.getElementById('home-content').style.display = 'block';
|
||||
document.getElementById('tabs').style.display = 'none';
|
||||
document.getElementById('stats-bar').style.display = 'none';
|
||||
document.getElementById('cmds-container').style.display = 'none';
|
||||
document.getElementById('home-btn').style.display = 'none';
|
||||
document.getElementById('os-title').textContent = 'SysCmd';
|
||||
document.getElementById('os-sub').textContent = '';
|
||||
document.getElementById('breadcrumb').innerHTML = '';
|
||||
document.getElementById('footer-hint').textContent = 'Cliquez sur un OS pour explorer ses commandes';
|
||||
renderHome();
|
||||
}
|
||||
|
||||
function hideHome() {
|
||||
document.getElementById('home-content').style.display = 'none';
|
||||
document.getElementById('tabs').style.display = 'flex';
|
||||
document.getElementById('stats-bar').style.display = 'flex';
|
||||
document.getElementById('cmds-container').style.display = 'block';
|
||||
document.getElementById('footer-hint').textContent = 'Cliquez sur une commande pour la copier';
|
||||
}
|
||||
|
||||
// ── RENDER HOME ──
|
||||
function renderHome() {
|
||||
renderStats();
|
||||
renderCards();
|
||||
}
|
||||
|
||||
function renderStats() {
|
||||
var totalCmds = ALL_COMMANDS.length;
|
||||
var totalSections = 0;
|
||||
for (var k in SEC) if (SEC.hasOwnProperty(k)) totalSections++;
|
||||
var totalOS = 0;
|
||||
var leaves = collectLeafNodes(TREE, []);
|
||||
for (var i = 0; i < leaves.length; i++) if (leaves[i].sectionIds) totalOS++;
|
||||
|
||||
var el = document.getElementById('stats-row');
|
||||
el.innerHTML =
|
||||
'<div class="bg-white border border-[#e2e8f0] rounded-xl p-3"><div class="stat-value text-[#0f172a]">' + totalCmds + '</div><div class="text-xs text-[#94a3b8]">commandes</div></div>' +
|
||||
'<div class="bg-white border border-[#e2e8f0] rounded-xl p-3"><div class="stat-value text-[#0f172a]">' + totalSections + '</div><div class="text-xs text-[#94a3b8]">sections</div></div>' +
|
||||
'<div class="bg-white border border-[#e2e8f0] rounded-xl p-3"><div class="stat-value text-[#0f172a]">' + totalOS + '</div><div class="text-xs text-[#94a3b8]">OS renseignés</div></div>' +
|
||||
'<div class="bg-white border border-[#e2e8f0] rounded-xl p-3"><div class="stat-value text-[#94a3b8]">' + (leaves.length - totalOS) + '</div><div class="text-xs text-[#94a3b8]">placeholders</div></div>';
|
||||
}
|
||||
|
||||
var OS_CARDS = [
|
||||
// OS category
|
||||
{ id: 'debian', label: 'Debian', icon: 'D', color: '#0f172a', desc: t('Distribution stable de référence', 'Stable reference distribution'), cat: 'os' },
|
||||
{ id: 'ubuntu', label: 'Ubuntu', icon: 'U', color: '#dc2626', desc: t('Basé sur Debian avec versions LTS', 'Debian-based with LTS releases'), cat: 'os', isGroup: true },
|
||||
{ id: 'oracle', label: 'Oracle Linux', icon: 'O', color: '#b9141e', desc: t('Linux Oracle avec UEK + SELinux', 'Oracle Linux with UEK + SELinux'), cat: 'os' },
|
||||
{ id: 'windows', label: 'Windows', icon: 'W', color: '#0078d4', desc: t('CMD + PowerShell client/server', 'CMD + PowerShell client/server'), cat: 'os', isGroup: true },
|
||||
{ id: 'solaris', label: 'Solaris', icon: 'S', color: '#b46400', desc: t('Solaris / illumos avec ZFS + DTrace', 'Solaris / illumos with ZFS + DTrace'), cat: 'os' },
|
||||
{ id: 'rhel', label: 'RHEL / CentOS', icon: 'R', color: '#94a3b8', desc: t('Enterprise Linux (à venir)', 'Enterprise Linux (pending)'), cat: 'os', placeholder: true },
|
||||
{ id: 'fedora', label: 'Fedora', icon: 'F', color: '#94a3b8', desc: t('Basé sur RHEL (à venir)', 'RHEL-based (pending)'), cat: 'os', placeholder: true },
|
||||
{ id: 'macos', label: 'macOS', icon: 'M', color: '#94a3b8', desc: t('macOS (à venir)', 'macOS (pending)'), cat: 'os', placeholder: true },
|
||||
// Docker category
|
||||
{ id: 'docker-compose', label: 'Docker Compose', icon: 'D', color: '#0ea5e9', desc: t('Orchestration multi-conteneurs', 'Multi-container orchestration'), cat: 'docker', placeholder: true },
|
||||
{ id: 'docker-swarm', label: 'Docker Swarm', icon: 'S', color: '#0ea5e9', desc: t('Cluster Docker natif', 'Native Docker clustering'), cat: 'docker', placeholder: true },
|
||||
{ id: 'dockerfile', label: 'Dockerfile', icon: 'F', color: '#0ea5e9', desc: t('Instructions de build', 'Build instructions'), cat: 'docker', placeholder: true },
|
||||
// Other category
|
||||
{ id: 'cisco', label: 'Cisco IOS', icon: 'C', color: '#8b5cf6', desc: t('Réseau Cisco (à venir)', 'Cisco networking (pending)'), cat: 'other', placeholder: true },
|
||||
{ id: 'mysql', label: 'MySQL / MariaDB', icon: 'S', color: '#8b5cf6', desc: t('Bases de données SQL (à venir)', 'SQL databases (pending)'), cat: 'other', placeholder: true },
|
||||
{ id: 'postgresql', label: 'PostgreSQL', icon: 'P', color: '#8b5cf6', desc: t('Base de données avancée (à venir)', 'Advanced database (pending)'), cat: 'other', placeholder: true },
|
||||
{ id: 'ansible', label: 'Ansible', icon: 'A', color: '#8b5cf6', desc: t('Automatisation IT (à venir)', 'IT automation (pending)'), cat: 'other', placeholder: true },
|
||||
{ id: 'kubernetes', label: 'Kubernetes', icon: 'K', color: '#8b5cf6', desc: t('Orchestration conteneurs (à venir)', 'Container orchestration (pending)'), cat: 'other', placeholder: true },
|
||||
];
|
||||
|
||||
function renderCards() {
|
||||
var el = document.getElementById('card-grid');
|
||||
el.innerHTML = '';
|
||||
var cats = { os: { label: t('Systèmes d\'exploitation', 'Operating Systems'), html: '' }, docker: { label: t('Docker / Conteneurs', 'Docker / Containers'), html: '' }, other: { label: t('Réseau, BDD, DevOps', 'Network, DB, DevOps'), html: '' } };
|
||||
OS_CARDS.forEach(function(card) {
|
||||
card.cat = card.cat || 'other';
|
||||
if (!cats[card.cat]) cats[card.cat] = { label: card.cat, html: '' };
|
||||
var div = document.createElement('div');
|
||||
var isPlaceholder = card.placeholder;
|
||||
var node = findNode(TREE, card.id);
|
||||
var cnt = node ? countNodeCmds(node) : 0;
|
||||
if (cnt > 0) isPlaceholder = false;
|
||||
|
||||
div.className = 'os-card' + (isPlaceholder ? ' placeholder-card' : '');
|
||||
|
||||
var iconBg = isPlaceholder ? 'bg-[#e2e8f0] text-[#94a3b8]' : 'text-white';
|
||||
div.innerHTML =
|
||||
'<div class="flex items-start gap-3 mb-3">' +
|
||||
'<div class="icon ' + iconBg + '" style="' + (isPlaceholder ? '' : 'background:' + card.color) + '">' +
|
||||
'<span class="font-bold text-sm">' + card.icon + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="flex-1 min-w-0">' +
|
||||
'<div class="font-semibold text-sm truncate">' + (card.isGroup ? card.label + ' →' : card.label) + '</div>' +
|
||||
'<div class="sublabel">' + card.desc.fr + '</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="flex items-center gap-2 text-xs">' +
|
||||
(cnt > 0 ? '<span class="font-semibold text-[#0f172a]">' + cnt + '</span><span class="text-[#94a3b8]">commandes</span>' : '<span class="text-[#cbd5e1]">' + (isPlaceholder ? 'À venir' : 'via sidebar') + '</span>') +
|
||||
'</div>';
|
||||
|
||||
div.onclick = function() {
|
||||
if (card.isGroup) {
|
||||
var n = findNode(TREE, card.id);
|
||||
if (n && n.children && n.children.length > 0) {
|
||||
selectNode(n.children[0]);
|
||||
}
|
||||
} else if (node) {
|
||||
selectNode(node);
|
||||
}
|
||||
};
|
||||
|
||||
cats[card.cat].html += div.outerHTML;
|
||||
});
|
||||
|
||||
// Render categories
|
||||
var html = '';
|
||||
Object.keys(cats).forEach(function(k) {
|
||||
html += '<div class="col-span-full text-xs font-semibold uppercase tracking-wider text-[#94a3b8] mt-2 mb-1">' + cats[k].label.fr + '</div>';
|
||||
html += cats[k].html;
|
||||
});
|
||||
el.innerHTML = html;
|
||||
}
|
||||
|
||||
// ── SHOW COMMANDS ──
|
||||
function showCmds(commands) {
|
||||
var el = document.getElementById('cmds');
|
||||
var sv = document.getElementById('search').value.trim().toLowerCase();
|
||||
|
||||
var cmds = commands;
|
||||
if (sv) {
|
||||
cmds = cmds.filter(function(x) {
|
||||
return x.d.fr.toLowerCase().indexOf(sv) !== -1 || x.d.en.toLowerCase().indexOf(sv) !== -1 || x.c.toLowerCase().indexOf(sv) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('shown').textContent = '' + cmds.length;
|
||||
|
||||
if (cmds.length === 0) {
|
||||
el.innerHTML = '<div class="p-8 text-center text-sm text-[#94a3b8]">Aucune commande trouvée</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
el.innerHTML = '';
|
||||
for (var i = 0; i < cmds.length; i++) {
|
||||
var x = cmds[i];
|
||||
var row = document.createElement('div');
|
||||
row.className = 'cmd-row' + (i % 2 === 0 ? ' bg-[#fafbfc]' : '');
|
||||
row.innerHTML = '<div class="cmd-desc">' + x.d.fr + '</div><div class="cmd-text"><span class="copy-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg></span><span>' + x.c + '</span></div>';
|
||||
row.querySelector('.cmd-text').onclick = (function(cmd) {
|
||||
return function() {
|
||||
navigator.clipboard.writeText(cmd).then(function() {
|
||||
var icon = row.querySelector('.copy-icon');
|
||||
icon.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>';
|
||||
setTimeout(function() { icon.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>'; }, 1200);
|
||||
});
|
||||
};
|
||||
})(x.c);
|
||||
el.appendChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
// ── SEARCH ──
|
||||
function filterCommands(val) {
|
||||
var el = document.getElementById('filter-info');
|
||||
el.textContent = val.trim() ? 'Filtre: "' + val + '"' : 'Aucun filtre';
|
||||
if (currentNode && currentNode._sectionId) {
|
||||
showCmds(SEC[currentNode._sectionId].commands);
|
||||
} else if (currentNode && currentNode.sectionIds && currentNode.sectionIds.length > 0) {
|
||||
showCmds(SEC[currentNode.sectionIds[0]].commands);
|
||||
}
|
||||
}
|
||||
|
||||
// ── GLOBAL SEARCH ──
|
||||
function globalSearch(val) {
|
||||
var el = document.getElementById('global-search-results');
|
||||
var cmdsEl = document.getElementById('global-cmds');
|
||||
var sv = val.trim().toLowerCase();
|
||||
|
||||
if (!sv) {
|
||||
el.style.display = 'none';
|
||||
document.getElementById('card-grid').style.display = 'grid';
|
||||
document.getElementById('stats-row').style.display = 'grid';
|
||||
return;
|
||||
}
|
||||
|
||||
el.style.display = 'block';
|
||||
document.getElementById('card-grid').style.display = 'none';
|
||||
document.getElementById('stats-row').style.display = 'none';
|
||||
|
||||
// Search across all commands
|
||||
var results = [];
|
||||
for (var i = 0; i < ALL_COMMANDS.length; i++) {
|
||||
var x = ALL_COMMANDS[i];
|
||||
if (x.d.fr.toLowerCase().indexOf(sv) !== -1 || x.d.en.toLowerCase().indexOf(sv) !== -1 || x.c.toLowerCase().indexOf(sv) !== -1) {
|
||||
results.push(x);
|
||||
}
|
||||
}
|
||||
|
||||
cmdsEl.innerHTML = '';
|
||||
if (results.length === 0) {
|
||||
cmdsEl.innerHTML = '<div class="p-8 text-center text-sm text-[#94a3b8]">Aucune commande trouvée</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Header stat
|
||||
var header = document.createElement('div');
|
||||
header.className = 'px-4 py-2 text-xs text-[#94a3b8] border-b border-[#f1f5f9]';
|
||||
header.textContent = results.length + ' résultat(s) dans toutes les sections';
|
||||
cmdsEl.appendChild(header);
|
||||
|
||||
for (var j = 0; j < results.length; j++) {
|
||||
var x = results[j];
|
||||
var row = document.createElement('div');
|
||||
row.className = 'cmd-row' + (j % 2 === 0 ? ' bg-[#fafbfc]' : '');
|
||||
row.innerHTML = '<div class="cmd-desc">' + x.d.fr + '</div><div class="cmd-text"><span class="copy-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg></span><span>' + x.c + '</span></div>';
|
||||
row.querySelector('.cmd-text').onclick = (function(cmd) {
|
||||
return function() {
|
||||
navigator.clipboard.writeText(cmd).then(function() {
|
||||
var icon = row.querySelector('.copy-icon');
|
||||
icon.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>';
|
||||
setTimeout(function() { icon.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>'; }, 1200);
|
||||
});
|
||||
};
|
||||
})(x.c);
|
||||
cmdsEl.appendChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
// ── INIT ──
|
||||
renderTree();
|
||||
showHome();
|
||||
Reference in New Issue
Block a user