Sidebar implemented

This commit is contained in:
Moira Daniella A Sebastian
2026-02-17 21:25:26 +01:00
parent bc560c7488
commit 43bffbbeb6
11 changed files with 3901 additions and 57 deletions

View File

@@ -10,11 +10,34 @@ templ Layout(props LayoutProps) {
<meta name="description" content={ props.Description }/>
@Head(props.Head)
</head>
<body>
<body class="min-h-screen bg-base-200 text-base-content flex flex-col">
@Header(props.Header)
<main>
<div class="flex flex-1 min-h-0">
@Sidebar(props.Routes)
<main class="flex-1 p-4 bg-base-100 min-h-0 overflow-auto">
{ children... }
</main>
</div>
<script>
function toggleSidebar() {
const sidebar = document.getElementById("sidebar");
if (!sidebar) return;
const labels = sidebar.querySelectorAll(".sidebar-label");
const links = sidebar.querySelectorAll(".sidebar-link, .sidebar-toggle");
sidebar.classList.toggle("w-56");
sidebar.classList.toggle("w-16");
labels.forEach(label => {
label.classList.toggle("hidden");
});
links.forEach(link => {
link.classList.toggle("justify-start");
link.classList.toggle("justify-center");
link.classList.toggle("gap-3");
link.classList.toggle("gap-0");
});
}
</script>
</body>
</html>
}
@@ -24,6 +47,12 @@ type LayoutProps struct {
Description string
Head HeadProps
Header HeaderProps
Routes []NavRoutes
}
type NavRoutes struct {
Name string
Path string
Icon templ.Component
}
templ Head(props HeadProps) {

View File

@@ -63,7 +63,7 @@ func Layout(props LayoutProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</head><body>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</head><body class=\"min-h-screen bg-base-200 text-base-content flex flex-col\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -71,7 +71,15 @@ func Layout(props LayoutProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<main>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div class=\"flex flex-1 min-h-0\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = Sidebar(props.Routes).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<main class=\"flex-1 p-4 bg-base-100 min-h-0 overflow-auto\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -79,7 +87,7 @@ func Layout(props LayoutProps) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</main></body></html>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</main></div><script>\n\t\t\tfunction toggleSidebar() {\n\tconst sidebar = document.getElementById(\"sidebar\");\n\tif (!sidebar) return;\n\tconst labels = sidebar.querySelectorAll(\".sidebar-label\");\n\tconst links = sidebar.querySelectorAll(\".sidebar-link, .sidebar-toggle\");\n\t\tsidebar.classList.toggle(\"w-56\");\n\tsidebar.classList.toggle(\"w-16\");\n\tlabels.forEach(label => {\n\t\tlabel.classList.toggle(\"hidden\");\n\t});\n\tlinks.forEach(link => {\n\t\tlink.classList.toggle(\"justify-start\");\n\t\tlink.classList.toggle(\"justify-center\");\n\t\tlink.classList.toggle(\"gap-3\");\n\t\tlink.classList.toggle(\"gap-0\");\n\t});\n}\n\t\t\t</script></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -92,6 +100,12 @@ type LayoutProps struct {
Description string
Head HeadProps
Header HeaderProps
Routes []NavRoutes
}
type NavRoutes struct {
Name string
Path string
Icon templ.Component
}
func Head(props HeadProps) templ.Component {
@@ -116,78 +130,78 @@ func Head(props HeadProps) templ.Component {
}
ctx = templ.ClearChildren(ctx)
for _, link := range props.Links {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<link href=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<link href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 templ.SafeURL
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(link.Href)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 31, Col: 24}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 60, Col: 24}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\" rel=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\" rel=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(link.Rel)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 31, Col: 41}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 60, Col: 41}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "\" as=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\" as=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(link.As)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 31, Col: 56}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 60, Col: 56}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
for _, script := range props.Scripts {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<script src=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<script src=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(script.Src)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 34, Col: 26}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 63, Col: 26}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" defer=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\" defer=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(script.Defer)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 34, Col: 49}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 63, Col: 49}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\"></script>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\"></script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -233,20 +247,20 @@ func Header(props HeaderProps) templ.Component {
templ_7745c5c3_Var10 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<header class=\"navbar bg-primary text-primary-content px-6\"><div class=\"navbar-start\"><span class=\"font-semibold mr-5\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<header class=\"navbar bg-primary text-primary-content px-6\"><div class=\"navbar-start\"><span class=\"font-semibold mr-5\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(props.Title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 57, Col: 49}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/layout.templ`, Line: 86, Col: 49}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</span></div><div class=\"navbar-center\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</span></div><div class=\"navbar-center\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -256,7 +270,7 @@ func Header(props HeaderProps) templ.Component {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</div><div class=\"navbar-end\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div><div class=\"navbar-end\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -266,7 +280,7 @@ func Header(props HeaderProps) templ.Component {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div></header>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div></header>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@@ -0,0 +1,37 @@
package components
templ Sidebar(routes []NavRoutes) {
<aside
id="sidebar"
class="w-56 shrink-0 flex flex-col min-h-0 bg-base-100 border-r border-base-300 shadow-sm transition-all duration-300"
>
<nav class="flex-1 overflow-y-auto py-3 px-2">
<ul class="menu menu-vertical w-full p-0 gap-0.5">
for _, r := range routes {
<li>
<a
href={ r.Path }
class="sidebar-link rounded-lg py-2.5 px-3 text-base-content font-medium no-underline hover:bg-base-200 active:bg-base-200 transition-colors duration-150 flex items-center gap-3 min-w-0"
>
if r.Icon != nil {
<span class="sidebar-icon shrink-0 flex items-center justify-center [&>svg]:w-5 [&>svg]:h-5">@r.Icon</span>
}
<span class="sidebar-label truncate">{ r.Name }</span>
</a>
</li>
}
</ul>
</nav>
<div class="border-t border-base-300 p-2 shrink-0">
<button
type="button"
class="sidebar-toggle btn btn-ghost btn-sm w-full justify-start text-base-content/80 hover:text-base-content hover:bg-base-200 rounded-lg flex items-center gap-3"
onclick="toggleSidebar()"
aria-label="Collapse sidebar"
>
<span class="sidebar-icon shrink-0">@IconCollapse()</span>
<span class="sidebar-label">Collapse</span>
</button>
</div>
</aside>
}

View File

@@ -0,0 +1,102 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.977
package components
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Sidebar(routes []NavRoutes) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<aside id=\"sidebar\" class=\"w-56 shrink-0 flex flex-col min-h-0 bg-base-100 border-r border-base-300 shadow-sm transition-all duration-300\"><nav class=\"flex-1 overflow-y-auto py-3 px-2\"><ul class=\"menu menu-vertical w-full p-0 gap-0.5\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
for _, r := range routes {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<li><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 templ.SafeURL
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs(r.Path)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/sidebar.templ`, Line: 13, Col: 20}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\" class=\"sidebar-link rounded-lg py-2.5 px-3 text-base-content font-medium no-underline hover:bg-base-200 active:bg-base-200 transition-colors duration-150 flex items-center gap-3 min-w-0\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if r.Icon != nil {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<span class=\"sidebar-icon shrink-0 flex items-center justify-center [&>svg]:w-5 [&>svg]:h-5\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = r.Icon.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</span> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<span class=\"sidebar-label truncate\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(r.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `pkg/web/components/sidebar.templ`, Line: 19, Col: 52}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</span></a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</ul></nav><div class=\"border-t border-base-300 p-2 shrink-0\"><button type=\"button\" class=\"sidebar-toggle btn btn-ghost btn-sm w-full justify-start text-base-content/80 hover:text-base-content hover:bg-base-200 rounded-lg flex items-center gap-3\" onclick=\"toggleSidebar()\" aria-label=\"Collapse sidebar\"><span class=\"sidebar-icon shrink-0\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = IconCollapse().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</span> <span class=\"sidebar-label\">Collapse</span></button></div></aside>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate