Version mono-fichier : plus de dependances externes (Tailwind/Fonts/scipt.js separe)

This commit is contained in:
2026-08-14 13:53:50 +02:00
parent 90e0d4eb7d
commit 5c31c2fb5f
2 changed files with 408 additions and 738 deletions
+408 -147
View File
@@ -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>
<div>
<div class="breadcrumb" id="breadcrumb"></div>
<h1 class="text-xl font-bold" id="os-title"></h1>
<p class="text-xs text-[#64748b] mt-0.5" id="os-sub"></p>
</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">SysCmd</h1>
<p class="text-xs text-[#64748b] mt-0.5" id="os-sub"></p>
</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>
<div id="global-search-results" style="display:none;margin-bottom:1.5rem"></div>
<!-- STATS ROW -->
<div class="grid grid-cols-4 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 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 class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3" id="card-grid"></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&&currentNode._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,'&quot;');
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&&currentNode._sectionId){showCmds(SEC[currentNode._sectionId].commands);return}
if(currentNode&&currentNode.sectionIds&&currentNode.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>