mirror of
https://github.com/juanfont/headscale.git
synced 2026-04-14 12:59:56 +02:00
templates: add error box component and error page template
Add errorBox() and errorIcon() to the design system, mirroring the existing successBox()/checkboxIcon() pattern with red error styling. Extract error color constants from the inline values in statusMessage(). Add AuthError() template that renders a styled HTML error page using the same HtmlStructure/mdTypesetBody/logo/footer as all other browser-facing pages. Updates juanfont/headscale#3182
This commit is contained in:
41
hscontrol/templates/auth_error.go
Normal file
41
hscontrol/templates/auth_error.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"github.com/chasefleming/elem-go"
|
||||
)
|
||||
|
||||
// AuthErrorResult contains the text content for an error page shown
|
||||
// to users in their browser when a browser-facing operation fails
|
||||
// (OIDC callback, SSH check, registration confirmation, etc.).
|
||||
type AuthErrorResult struct {
|
||||
// Title is the browser tab / page title,
|
||||
// e.g. "Headscale - Error".
|
||||
Title string
|
||||
|
||||
// Heading is the bold red text inside the error box,
|
||||
// e.g. "Forbidden".
|
||||
Heading string
|
||||
|
||||
// Message is the actionable user-facing message shown below
|
||||
// the heading, e.g. "You are not authorized. Please contact
|
||||
// your administrator."
|
||||
Message string
|
||||
}
|
||||
|
||||
// AuthError renders a styled error page for browser-facing failures.
|
||||
// The caller controls every user-visible string via [AuthErrorResult].
|
||||
func AuthError(result AuthErrorResult) *elem.Element {
|
||||
box := errorBox(
|
||||
result.Heading,
|
||||
elem.Text(result.Message),
|
||||
)
|
||||
|
||||
return HtmlStructure(
|
||||
elem.Title(nil, elem.Text(result.Title)),
|
||||
mdTypesetBody(
|
||||
headscaleLogo(),
|
||||
box,
|
||||
pageFooter(),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -39,6 +39,10 @@ const (
|
||||
// Success colors.
|
||||
colorSuccess = "#059669" //nolint:unused // Success states
|
||||
colorSuccessLight = "#d1fae5" //nolint:unused // Success backgrounds
|
||||
|
||||
// Error colors.
|
||||
colorError = "#dc2626" //nolint:unused // Error states (red-600)
|
||||
colorErrorLight = "#fee2e2" //nolint:unused // Error backgrounds (red-100)
|
||||
)
|
||||
|
||||
// Spacing System
|
||||
@@ -406,6 +410,47 @@ func checkboxIcon() elem.Node {
|
||||
</svg>`)
|
||||
}
|
||||
|
||||
// errorBox creates a red error feedback box with an X-circle icon.
|
||||
// The heading is displayed as bold red text, and children are rendered below it.
|
||||
// Pairs with successBox for consistent feedback styling.
|
||||
//
|
||||
//nolint:unused // Used in auth_error.go template.
|
||||
func errorBox(heading string, children ...elem.Node) *elem.Element {
|
||||
return elem.Div(attrs.Props{
|
||||
attrs.Style: styles.Props{
|
||||
styles.Display: "flex",
|
||||
styles.AlignItems: "center",
|
||||
styles.Gap: spaceM,
|
||||
styles.Padding: spaceL,
|
||||
styles.BackgroundColor: colorErrorLight,
|
||||
styles.Border: "1px solid " + colorError,
|
||||
styles.BorderRadius: "0.5rem",
|
||||
styles.MarginBottom: spaceXL,
|
||||
}.ToInline(),
|
||||
},
|
||||
errorIcon(),
|
||||
elem.Div(nil,
|
||||
append([]elem.Node{
|
||||
elem.Strong(attrs.Props{
|
||||
attrs.Style: styles.Props{
|
||||
styles.Display: "block",
|
||||
styles.Color: colorError,
|
||||
styles.FontSize: fontSizeH3,
|
||||
styles.MarginBottom: spaceXS,
|
||||
}.ToInline(),
|
||||
}, elem.Text(heading)),
|
||||
}, children...)...,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// errorIcon returns the error X-circle SVG icon as raw HTML.
|
||||
func errorIcon() elem.Node {
|
||||
return elem.Raw(`<svg id="error-icon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 512 512">
|
||||
<path fill="#dc2626" d="M256 32C132.3 32 32 132.3 32 256s100.3 224 224 224 224-100.3 224-224S379.7 32 256 32zm97.7 272.7c6.2 6.2 6.2 16.4 0 22.6-3.1 3.1-7.2 4.7-11.3 4.7s-8.2-1.6-11.3-4.7L256 251.3l-75.1 76c-3.1 3.1-7.2 4.7-11.3 4.7s-8.2-1.6-11.3-4.7c-6.2-6.2-6.2-16.4 0-22.6l75.1-76-75.1-76c-6.2-6.2-6.2-16.4 0-22.6s16.4-6.2 22.6 0l75.1 76 75.1-76c6.2-6.2 16.4-6.2 22.6 0s6.2 16.4 0 22.6L278.6 229l75.1 75.7z"></path>
|
||||
</svg>`)
|
||||
}
|
||||
|
||||
// warningBox creates a warning message box with icon and content.
|
||||
//
|
||||
//nolint:unused // Used in apple.go template.
|
||||
@@ -504,8 +549,8 @@ func statusMessage(message string, isSuccess bool) *elem.Element {
|
||||
textColor := colorSuccess
|
||||
|
||||
if !isSuccess {
|
||||
bgColor = "#fee2e2" // red-100
|
||||
textColor = "#dc2626" // red-600
|
||||
bgColor = colorErrorLight
|
||||
textColor = colorError
|
||||
}
|
||||
|
||||
return elem.Div(attrs.Props{
|
||||
|
||||
Reference in New Issue
Block a user