170 lines
8.2 KiB
Plaintext
170 lines
8.2 KiB
Plaintext
package templates
|
|
|
|
import "dealroom/internal/model"
|
|
import "dealroom/internal/rbac"
|
|
|
|
templ Layout(profile *model.Profile, activePage string) {
|
|
<!DOCTYPE html>
|
|
<html lang="en" class="dark">
|
|
<head>
|
|
<meta charset="UTF-8"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>Dealspace AI</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
|
<link rel="stylesheet" href="/static/styles.css"/>
|
|
<script>
|
|
tailwind.config = {
|
|
darkMode: 'class',
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
atlas: '#14B8A6',
|
|
'atlas-surface': 'rgba(20,184,166,0.1)',
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</head>
|
|
<body class="bg-gray-950 text-gray-100 min-h-screen flex">
|
|
<!-- Sidebar -->
|
|
<aside class="w-60 bg-gray-900 border-r border-gray-800 flex flex-col fixed h-full">
|
|
<!-- Brand -->
|
|
<div class="p-4 border-b border-gray-800">
|
|
<div class="flex items-center gap-2">
|
|
<div class="w-8 h-8 rounded-lg bg-teal-500 flex items-center justify-center">
|
|
<svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4"></path></svg>
|
|
</div>
|
|
<span class="font-bold text-lg">Dealspace AI</span>
|
|
</div>
|
|
<div class="mt-3 flex items-center gap-2">
|
|
<div class="w-6 h-6 rounded-full bg-teal-500/20 flex items-center justify-center text-xs font-bold text-teal-400">A</div>
|
|
<span class="text-xs text-gray-400">Apex Capital Partners</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Navigation -->
|
|
<nav class="flex-1 p-3 space-y-1">
|
|
@sidebarLink("/", "Dashboard", activePage == "dashboard", svgDashboard())
|
|
if rbac.IsSeller(profile.Role) {
|
|
@sidebarLink("/deals", "Deal Rooms", activePage == "deals", svgFolder())
|
|
@sidebarLink("/requests", "Request Lists", activePage == "requests", svgClipboard())
|
|
@sidebarLink("/analytics", "Analytics", activePage == "analytics", svgChart())
|
|
@sidebarLink("/contacts", "Contacts", activePage == "contacts", svgUsers())
|
|
@sidebarLink("/team", "Team", activePage == "team", svgTeam())
|
|
@sidebarLink("/audit", "Audit Log", activePage == "audit", svgShield())
|
|
@sidebarLink("/admin", "Admin", activePage == "admin", svgCog())
|
|
}
|
|
if rbac.IsBuyer(profile.Role) {
|
|
@sidebarLink("/deals", "Deal Rooms", activePage == "deals", svgFolder())
|
|
@sidebarLink("/requests", "Request Lists", activePage == "requests", svgClipboard())
|
|
}
|
|
</nav>
|
|
|
|
<!-- Atlas AI -->
|
|
<div class="p-3">
|
|
<div class="rounded-lg border border-teal-500/30 bg-teal-500/5 p-3">
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<div class="w-5 h-5 rounded bg-teal-500/20 flex items-center justify-center">
|
|
<svg class="w-3 h-3 text-teal-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg>
|
|
</div>
|
|
<span class="text-xs font-semibold text-teal-400">Atlas AI</span>
|
|
</div>
|
|
<p class="text-xs text-gray-500">Ask anything about your deal room documents.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- User -->
|
|
<div class="p-3 border-t border-gray-800">
|
|
<div class="flex items-center gap-2">
|
|
<div class="w-8 h-8 rounded-full bg-teal-500/20 flex items-center justify-center text-xs font-bold text-teal-400">
|
|
{ initials(profile.FullName) }
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-medium truncate">{ profile.FullName }</p>
|
|
<p class="text-xs text-gray-500 truncate">
|
|
if rbac.IsSeller(profile.Role) {
|
|
Seller
|
|
} else {
|
|
Buyer
|
|
}
|
|
</p>
|
|
</div>
|
|
<a href="/auth/logout" class="text-gray-500 hover:text-gray-300">
|
|
<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="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Main Content -->
|
|
<main class="ml-60 flex-1 min-h-screen">
|
|
<div class="p-6">
|
|
{ children... }
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
}
|
|
|
|
func initials(name string) string {
|
|
if len(name) == 0 {
|
|
return "?"
|
|
}
|
|
result := ""
|
|
prev := ' '
|
|
for i, c := range name {
|
|
if i == 0 || prev == ' ' {
|
|
result += string(c)
|
|
}
|
|
prev = c
|
|
}
|
|
if len(result) > 2 {
|
|
result = result[:2]
|
|
}
|
|
return result
|
|
}
|
|
|
|
templ sidebarLink(href string, label string, active bool, icon templ.Component) {
|
|
<a href={ templ.SafeURL(href) }
|
|
class={ "flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition",
|
|
templ.KV("bg-teal-500/10 text-teal-400 font-medium", active),
|
|
templ.KV("text-gray-400 hover:text-gray-200 hover:bg-gray-800", !active) }>
|
|
@icon
|
|
{ label }
|
|
</a>
|
|
}
|
|
|
|
templ svgDashboard() {
|
|
<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="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"></path></svg>
|
|
}
|
|
|
|
templ svgFolder() {
|
|
<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="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"></path></svg>
|
|
}
|
|
|
|
templ svgClipboard() {
|
|
<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="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg>
|
|
}
|
|
|
|
templ svgChart() {
|
|
<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="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path></svg>
|
|
}
|
|
|
|
templ svgUsers() {
|
|
<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 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
|
|
}
|
|
|
|
templ svgCog() {
|
|
<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="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
|
|
}
|
|
|
|
templ svgTeam() {
|
|
<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="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
|
|
}
|
|
|
|
templ svgShield() {
|
|
<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="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path></svg>
|
|
}
|