Hypercode/alex/hypercodePublic

Code

  1. hypercode
  2. views
  3. components
  4. header.go
header.go290 lines
package components

import (
	"strings"

	"github.com/hypercodehq/hypercode/database/models"
	"github.com/hypercodehq/hypercode/views/components/ui"
	html "github.com/hypercodehq/libhtml"
	"github.com/hypercodehq/libhtml/attr"
)

type HeaderData struct {
	User *models.User
}

func Header(data *HeaderData, children ...html.Node) html.Node {
	if data == nil {
		data = &HeaderData{}
	}

	return html.Header(
		attr.Class("bg-background border-b px-4 py-3 flex flex-wrap justify-between items-center gap-2"),
		html.Div(
			attr.Class("flex flex-wrap items-center gap-4"),
			html.A(
				attr.Href("/"),
				attr.DataTooltip("Go back home"),
				attr.DataSide("bottom"),
				html.Img(
					attr.Src("/logo.png"),
					attr.Alt("Hypercode"),
					attr.Class("h-7"),
				),
			),
			html.Group(children...),
		),
		html.Div(
			attr.Class("flex flex-wrap items-center gap-4"),
			html.IfElsef(
				data.User != nil,
				func() html.Node { return loggedInActions(data.User) },
				func() html.Node { return loggedOutActions() },
			),
		),
	)
}

func loggedInActions(user *models.User) html.Node {
	return html.Div(
		attr.Class("flex flex-wrap items-center gap-4"),
		createNewDropdown(),
		userAccountDropdown(user),
	)
}

func socialLinks() html.Node {
	return html.Div(
		attr.Class("flex flex-wrap items-center gap-2"),
		html.A(
			attr.Href("https://x.com/hypercode2099"),
			attr.Target("_blank"),
			attr.Rel("noopener noreferrer"),
			attr.AriaLabel("Follow us on X"),
			attr.DataTooltip("Follow us on X"),
			attr.DataSide("bottom"),
			attr.Class("btn-icon-ghost"),
			ui.SVGIcon(ui.IconTwitter, ""),
		),
		html.A(
			attr.Href("https://discord.gg/edDhNEvRv7"),
			attr.Target("_blank"),
			attr.Rel("noopener noreferrer"),
			attr.AriaLabel("Join our Discord"),
			attr.DataTooltip("Join our Discord"),
			attr.DataSide("bottom"),
			attr.Class("btn-icon-ghost"),
			ui.SVGIcon(ui.IconDiscord, ""),
		),
		html.A(
			attr.Href("https://bsky.app/profile/hypercode.ovh"),
			attr.Target("_blank"),
			attr.Rel("noopener noreferrer"),
			attr.AriaLabel("Follow us on Bluesky"),
			attr.DataTooltip("Follow us on Bluesky"),
			attr.DataSide("bottom"),
			attr.Class("btn-icon-ghost"),
			ui.SVGIcon(ui.IconBluesky, ""),
		),
		html.A(
			attr.Href("https://github.com/hypercodehq/hypercode"),
			attr.Target("_blank"),
			attr.Rel("noopener noreferrer"),
			attr.AriaLabel("Star us on GitHub"),
			attr.DataTooltip("Star us on GitHub"),
			attr.DataSide("bottom"),
			attr.Class("btn-icon-ghost"),
			ui.SVGIcon(ui.IconGitHub, ""),
		),
	)
}

func loggedOutActions() html.Node {
	return html.Div(
		attr.Class("flex flex-wrap items-center gap-4"),
		socialLinks(),
		html.A(
			attr.Href("/auth/sign-in"),
			attr.Class("btn-outline"),
			html.Text("Sign in"),
		),
		html.A(
			attr.Href("/auth/sign-up"),
			attr.Class("btn"),
			html.Text("Create an account"),
		),
	)
}

func createNewDropdown() html.Node {
	return html.Div(
		attr.Class("dropdown-menu"),
		html.Element("button",
			attr.Type("button"),
			attr.Id("create-new-trigger"),
			attr.Class("btn-icon-ghost"),
			attr.AriaHaspopup("menu"),
			attr.AriaControls("create-new-menu"),
			attr.AriaExpanded("false"),
			ui.SVGIcon(ui.IconPlus, ""),
		),
		html.Div(
			attr.Id("create-new-popover"),
			attr.DataPopover(""),
			attr.AriaHidden("true"),
			attr.Class("min-w-56 right-0 left-auto"),
			html.Div(
				attr.Role("menu"),
				attr.Id("create-new-menu"),
				attr.AriaLabelledby("create-new-trigger"),
				html.Div(
					attr.Role("group"),
					attr.AriaLabelledby("create-new-label"),
					html.Div(
						attr.Role("heading"),
						attr.Id("create-new-label"),
						html.Text("Create"),
					),
					html.Hr(attr.Role("separator")),
					html.A(
						attr.Class("cursor-pointer"),
						attr.Href("/repositories/new"),
						attr.Role("menuitem"),
						ui.SVGIcon(ui.IconRepository, ""),
						html.Text("New repository"),
					),
					html.Hr(attr.Role("separator")),
					html.A(
						attr.Class("cursor-pointer"),
						attr.Href("/organizations/new"),
						attr.Role("menuitem"),
						ui.SVGIcon(ui.IconBuilding, ""),
						html.Text("New organization"),
					),
				),
			),
		),
	)
}

func userAccountDropdown(user *models.User) html.Node {
	return html.Div(
		attr.Class("dropdown-menu"),
		html.Element("button",
			attr.Type("button"),
			attr.Id("user-account-trigger"),
			attr.Class("btn-icon-ghost size-9"),
			attr.AriaHaspopup("menu"),
			attr.AriaControls("user-account-menu"),
			attr.AriaExpanded("false"),
			html.Div(
				attr.Class("size-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xs font-medium"),
				html.Text(getUserInitials(user)),
			),
		),
		html.Div(
			attr.Id("user-account-popover"),
			attr.DataPopover(""),
			attr.AriaHidden("true"),
			attr.Class("min-w-56 right-0 left-auto"),
			html.Div(
				attr.Role("menu"),
				attr.Id("user-account-menu"),
				attr.AriaLabelledby("user-account-trigger"),
				html.Div(
					attr.Role("group"),
					attr.AriaLabelledby("user-label"),
					html.Div(
						attr.Role("heading"),
						attr.Id("user-label"),
						html.Text("@"+user.Username),
					),
					html.Hr(attr.Role("separator")),
					html.A(
						attr.Href("/"+user.Username),
						attr.Role("menuitem"),
						attr.Class("cursor-pointer"),
						ui.SVGIcon(ui.IconUser, ""),
						html.Text("Profile"),
					),
					html.A(
						attr.Href("/settings"),
						attr.Role("menuitem"),
						attr.Class("cursor-pointer"),
						ui.SVGIcon(ui.IconSettings, ""),
						html.Text("Settings"),
					),
					html.Hr(attr.Role("separator")),
					html.A(
						attr.Href("https://x.com/hypercode2099"),
						attr.Target("_blank"),
						attr.Rel("noopener noreferrer"),
						attr.Role("menuitem"),
						attr.Class("cursor-pointer"),
						ui.SVGIcon(ui.IconTwitter, ""),
						html.Text("Follow us on X"),
					),
					html.A(
						attr.Href("https://discord.gg/edDhNEvRv7"),
						attr.Target("_blank"),
						attr.Rel("noopener noreferrer"),
						attr.Role("menuitem"),
						attr.Class("cursor-pointer"),
						ui.SVGIcon(ui.IconDiscord, ""),
						html.Text("Join our Discord"),
					),
					html.A(
						attr.Href("https://bsky.app/profile/hypercode.ovh"),
						attr.Target("_blank"),
						attr.Rel("noopener noreferrer"),
						attr.Role("menuitem"),
						attr.Class("cursor-pointer"),
						ui.SVGIcon(ui.IconBluesky, ""),
						html.Text("Follow us on Bluesky"),
					),
					html.A(
						attr.Href("https://github.com/hypercodehq/hypercode"),
						attr.Target("_blank"),
						attr.Rel("noopener noreferrer"),
						attr.Role("menuitem"),
						attr.Class("cursor-pointer"),
						ui.SVGIcon(ui.IconGitHub, ""),
						html.Text("Star us on GitHub"),
					),
					html.Hr(attr.Role("separator")),
					html.A(
						attr.Href("/auth/sign-out"),
						attr.Role("menuitem"),
						attr.Class("cursor-pointer text-destructive"),
						ui.SVGIcon(ui.IconLogOut, "text-destructive"),
						html.Text("Sign out"),
					),
				),
			),
		),
	)
}

func getUserInitials(user *models.User) string {
	if user == nil || user.Username == "" {
		return "?"
	}
	if len(user.Username) >= 2 {
		return strings.ToUpper(user.Username[0:2])
	}
	return strings.ToUpper(string(user.Username[0]))
}

type MainHeaderData struct {
	User  *models.User
	Class string
}

func MainHeader(data *MainHeaderData) html.Node {
	return Header(&HeaderData{User: data.User}, html.A(
		attr.Class("btn-ghost "+data.Class),
		attr.Href("/explore/repositories"),
		html.Text("Explore"),
	))
}