fix: UI overhaul — align all HTMX views with Lumina Design System (46 fixes)
- All 7 pages rewritten: Dashboard, Terminal, Snippets, Keychain, SFTP, Settings, Brief - Apply consistent Lumina glassmorphic theme (rounded-2xl, shadows, borders, tracking) - Fix SVG icons not rendering — return template.HTML instead of string - Fix Alpine x-data scoping: terminal tabs, SFTP modals, snippet tag buttons - Fix dashboard search sending literal ?q=... - Rebuild CSS with all new Tailwind classes (62KB) - Add .air.toml with hot-reload config, docs/PERBAIKANUI.md checklist - Remove unused backup partials
This commit is contained in:
@@ -15,42 +15,105 @@
|
||||
<body class="bg-surface text-on-surface antialiased dot-grid min-h-screen">
|
||||
<div class="flex min-h-screen">
|
||||
{{template "nav" .}}
|
||||
<div class="flex-1 flex flex-col overflow-hidden">
|
||||
<div class="flex-1 flex flex-col overflow-hidden" x-data="terminalManager()" x-init="init()">
|
||||
<header class="h-14 border-b border-outline-variant/30 flex items-center gap-2 px-6 bg-white/70 backdrop-blur-md">
|
||||
<h1 class="text-lg font-semibold text-on-surface">{{.Title}}</h1>
|
||||
<h1 class="text-xl font-bold tracking-tight text-on-surface">{{.Title}}</h1>
|
||||
<span class="text-xs text-on-surface-variant mt-0.5">Interactive SSH shell with multi-tab session management</span>
|
||||
<div class="flex-1"></div>
|
||||
<button @click="addTab()"
|
||||
class="p-1.5 rounded-lg hover:bg-surface-container-low text-on-surface-variant hover:text-on-surface transition-colors" title="New Tab">
|
||||
class="p-1.5 rounded-lg bg-surface-container hover:bg-primary-container hover:text-on-primary-container text-on-surface-variant transition-all" title="New Tab">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
|
||||
</button>
|
||||
</header>
|
||||
<main id="main-content" class="flex-1 flex flex-col overflow-hidden bg-[#0d1117]"
|
||||
x-data="terminalManager()"
|
||||
x-init="init()">
|
||||
<!-- Tab bar -->
|
||||
<div class="flex items-center bg-[#161b22] border-b border-[#30363d] overflow-x-auto no-scrollbar shrink-0" style="height: 36px;">
|
||||
<template x-for="(tab, i) in tabs" :key="tab.id">
|
||||
<div @click="switchTab(i)"
|
||||
:class="activeTab === i ? 'bg-[#0d1117] text-white border-t-2 border-[#58a6ff]' : 'bg-[#161b22] text-[#8b949e] hover:text-[#c9d1d9]'"
|
||||
class="flex items-center gap-1.5 px-3 text-xs cursor-pointer border-r border-[#30363d] shrink-0 select-none"
|
||||
style="height: 34px; padding-top: 1px;">
|
||||
<span class="w-2 h-2 rounded-full" :class="tab.connected ? 'bg-[#3fb950]' : 'bg-[#8b949e]'"></span>
|
||||
<span x-text="tab.name"></span>
|
||||
<button @click.stop="closeTab(i)" class="ml-0.5 p-0.5 rounded hover:bg-[#30363d] text-[#8b949e] hover:text-white transition-colors">
|
||||
<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" d="M6 18L18 6M6 6l12 12"/></svg>
|
||||
<main id="main-content" class="flex-1 flex flex-col overflow-auto p-6">
|
||||
<div class="max-w-7xl mx-auto space-y-6 flex flex-col flex-1 min-h-0 w-full">
|
||||
<!-- Session Tab Toolbar -->
|
||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-outline-variant/30 pb-3">
|
||||
<div class="flex items-center gap-2 overflow-x-auto no-scrollbar scroll-smooth pr-6">
|
||||
<template x-for="(tab, i) in tabs" :key="tab.id">
|
||||
<div @click="switchTab(i)"
|
||||
:class="activeTab === i ? 'bg-white text-primary border-primary shadow-[0_-4px_12px_rgba(0,80,203,0.06)]' : 'bg-surface-container-low text-on-surface-variant hover:bg-surface-container border-transparent'"
|
||||
class="flex items-center gap-2 px-3.5 py-2 rounded-t-xl text-xs font-bold font-mono transition-all cursor-pointer border-t-2">
|
||||
<svg class="w-3.5 h-3.5" :class="activeTab === i ? 'text-primary' : 'text-outline'" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 17V7c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v10c0 .621-.504 1.125-1.125 1.125h-2.25A1.125 1.125 0 014 17zm6 0V7c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v10c0 .621-.504 1.125-1.125 1.125h-2.25A1.125 1.125 0 0110 17zm6 0V7c0-.621.504-1.125 1.125-1.125h2.25C19.496 5.875 20 6.379 20 7v10c0 .621-.504 1.125-1.125 1.125h-2.25A1.125 1.125 0 0116 17z"/></svg>
|
||||
<span class="truncate max-w-[120px]" x-text="tab.name"></span>
|
||||
<button @click.stop="closeTab(i)" class="p-0.5 hover:bg-black/10 rounded transition-colors">
|
||||
<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" d="M6 18L18 6M6 6l12 12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<button @click="addTab()"
|
||||
class="p-1.5 bg-surface-container hover:bg-primary-container hover:text-on-primary-container text-on-surface-variant rounded-lg transition-all" title="Open new terminal connection">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Terminal containers -->
|
||||
<div class="flex-1 relative">
|
||||
<template x-for="(tab, i) in tabs" :key="tab.id">
|
||||
<div :id="'terminal-container-' + tab.id"
|
||||
x-show="activeTab === i"
|
||||
class="absolute inset-0">
|
||||
<div class="flex items-center gap-4 text-xs font-mono shrink-0">
|
||||
<div class="flex items-center gap-1.5 text-secondary">
|
||||
<span class="w-2 h-2 rounded-full bg-secondary animate-pulse"></span>
|
||||
<span>SECURE CRYPTO PATH</span>
|
||||
</div>
|
||||
<div class="text-outline">
|
||||
HOST: <span class="text-on-surface font-semibold" x-text="tabs.length ? tabs[activeTab].host : '—'"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Terminal shell frame -->
|
||||
<div class="flex-1 bg-white border border-outline-variant rounded-2xl shadow-sm flex flex-col overflow-hidden min-h-0">
|
||||
<!-- Terminal Header -->
|
||||
<div class="px-4 py-2 bg-surface-container-low border-b border-outline-variant/30 flex justify-between items-center">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="w-3 h-3 rounded-full bg-error/80"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-primary-container/80"></span>
|
||||
<span class="w-3 h-3 rounded-full bg-secondary/80"></span>
|
||||
<span class="text-[10px] font-mono font-bold text-outline ml-2">ssh -i id_ed25519 root@<span x-text="tabs.length ? tabs[activeTab].host : '—'"></span></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button @click="clearBuffer()"
|
||||
class="text-[10px] uppercase font-bold text-outline hover:text-primary transition-colors flex items-center gap-1">
|
||||
<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" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182"/></svg>
|
||||
Clear Buffer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Console display -->
|
||||
<div class="flex-1 overflow-y-auto min-h-0 font-mono text-sm leading-relaxed p-5 bg-white" id="terminal-output">
|
||||
<template x-for="(line, idx) in history" :key="idx">
|
||||
<div :class="line.type === 'input' ? 'text-on-surface font-bold' : line.type === 'error' ? 'text-error bg-error-container/20 px-2.5 py-1 rounded-md' : line.type === 'success' ? 'text-secondary bg-secondary-container/10 px-2.5 py-1 rounded-md font-semibold' : 'text-[#2244aa]'"
|
||||
class="whitespace-pre-wrap" x-text="line.text"></div>
|
||||
</template>
|
||||
<div class="h-4"></div>
|
||||
</div>
|
||||
|
||||
<!-- Input prompt -->
|
||||
<form @submit.prevent="submitCommand()"
|
||||
class="p-3 border-t border-outline-variant/40 bg-surface-container-low flex items-center gap-2.5">
|
||||
<span class="font-mono text-xs font-bold text-primary pl-2 shrink-0 flex items-center gap-1">
|
||||
<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="M15.75 17.25L12 21m0 0l-3.75-3.75M12 21V3"/></svg>
|
||||
root@<span x-text="tabs.length ? tabs[activeTab].name : 'host'"></span>:~$
|
||||
</span>
|
||||
<input type="text" x-model="command" autofocus
|
||||
placeholder='Type a command (e.g. "help", "ls", "docker ps", "ping google.com")...'
|
||||
class="flex-1 bg-transparent border-none font-mono text-xs font-medium focus:ring-0 focus:outline-none text-on-surface p-0">
|
||||
<button type="submit"
|
||||
class="p-1.5 bg-primary text-white rounded-lg hover:bg-primary-container hover:text-on-primary-container transition-all" title="Execute Command">
|
||||
<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="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z"/></svg>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Shortcut pills -->
|
||||
<div class="flex flex-wrap items-center gap-2 text-[11px] font-mono font-bold text-on-surface-variant">
|
||||
<span class="text-outline">SHORTCUT SUGGESTIONS:</span>
|
||||
<button type="button" @click="insertCommand('help')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">help</button>
|
||||
<button type="button" @click="insertCommand('ls')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">ls</button>
|
||||
<button type="button" @click="insertCommand('docker ps')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">docker ps</button>
|
||||
<button type="button" @click="insertCommand('uname -a')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">uname -a</button>
|
||||
<button type="button" @click="insertCommand('ping 8.8.8.8')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">ping 8.8.8.8</button>
|
||||
<button type="button" @click="insertCommand('cat server.js')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">cat server.js</button>
|
||||
<button type="button" @click="insertCommand('keychain')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">keychain</button>
|
||||
<button type="button" @click="insertCommand('clear')" class="px-2.5 py-1 rounded-md bg-surface-container border border-outline-variant/30 hover:border-primary hover:bg-primary-container/10 transition-colors">clear</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user