mirror of
https://github.com/juanfont/headscale.git
synced 2025-11-24 03:17:40 -05:00
hscontrol/templates: refactor to use CSS classes and embedded files
Refactor template system to use go:embed for external assets and CSS classes for styling instead of inline styles: - general.go: Add go:embed directives for style.css and headscale.svg, replace inline styles with CSS classes (H1, H2, H3, P, etc.), add mdTypesetBody wrapper with Material for MkDocs styling - apple.go, oidc_callback.go, register_web.go, windows.go: Update to use new CSS-based helper functions (H1, H2, P, etc.) and mdTypesetBody for consistent layout This separates content from presentation, making templates easier to maintain and update. All styling is now centralized in style.css with Material for MkDocs design system.
This commit is contained in:
committed by
Kristoffer Dalby
parent
285c4e46a9
commit
3ed1067a95
@@ -3,221 +3,67 @@ package templates
|
||||
import (
|
||||
"github.com/chasefleming/elem-go"
|
||||
"github.com/chasefleming/elem-go/attrs"
|
||||
"github.com/chasefleming/elem-go/styles"
|
||||
)
|
||||
|
||||
// headscaleLogo returns the Headscale SVG logo as raw HTML
|
||||
func headscaleLogo() elem.Node {
|
||||
return elem.Raw(`<svg id="logo" width="146" height="51" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule: evenodd; clip-rule: evenodd; stroke-linejoin: round; stroke-miterlimit: 2;" viewBox="0 0 1280 640">
|
||||
<path d="M.08 0v-.736h.068v.3C.203-.509.27-.545.347-.545c.029 0 .055.005.079.015.024.01.045.025.062.045.017.02.031.045.041.075.009.03.014.065.014.105V0H.475v-.289C.475-.352.464-.4.443-.433.422-.466.385-.483.334-.483c-.027 0-.052.006-.075.017C.236-.455.216-.439.2-.419c-.017.02-.029.044-.038.072-.009.028-.014.059-.014.093V0H.08Z" style="fill: #f8b5cb; fill-rule: nonzero" transform="translate(32.92220721 521.8022953) scale(235.3092)"/>
|
||||
<path d="M.051-.264c0-.036.007-.071.02-.105.013-.034.031-.064.055-.09.023-.026.052-.047.086-.063.033-.015.071-.023.112-.023.039 0 .076.007.109.021.033.014.062.033.087.058.025.025.044.054.058.088.014.035.021.072.021.113v.005H.121c.001.031.007.059.018.084.01.025.024.047.042.065.018.019.04.033.065.043.025.01.052.015.082.015.026 0 .049-.003.069-.01.02-.007.038-.016.054-.028C.466-.102.48-.115.492-.13c.011-.015.022-.03.032-.046l.057.03C.556-.097.522-.058.48-.03.437-.001.387.013.328.013.284.013.245.006.21-.01.175-.024.146-.045.123-.07.1-.095.082-.125.07-.159.057-.192.051-.227.051-.264ZM.128-.32h.396C.51-.375.485-.416.449-.441.412-.466.371-.479.325-.479c-.048 0-.089.013-.123.039-.034.026-.059.066-.074.12Z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(177.16674681 521.8022953) scale(235.3092)"/>
|
||||
<path d="M.051-.267c0-.038.007-.074.021-.108.014-.033.033-.063.058-.088.025-.025.054-.045.087-.06.033-.015.069-.022.108-.022.043 0 .083.009.119.027.035.019.066.047.093.084v-.097h.067V0H.537v-.091C.508-.056.475-.029.44-.013.404.005.365.013.323.013.284.013.248.006.215-.01.182-.024.153-.045.129-.071.104-.096.085-.126.072-.16.058-.193.051-.229.051-.267Zm.279.218c.027 0 .054-.005.079-.015.025-.01.048-.024.068-.043.019-.018.035-.04.047-.067.012-.027.018-.056.018-.089 0-.031-.005-.059-.016-.086C.515-.375.501-.398.482-.417.462-.436.44-.452.415-.463.389-.474.361-.479.331-.479c-.031 0-.059.006-.084.017C.221-.45.199-.434.18-.415c-.019.02-.033.043-.043.068-.011.026-.016.053-.016.082 0 .029.005.056.016.082.011.026.025.049.044.069.019.02.041.036.066.047.025.012.053.018.083.018Z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(327.76463481 521.8022953) scale(235.3092)"/>
|
||||
<path d="M.051-.267c0-.038.007-.074.021-.108.014-.033.033-.063.058-.088.025-.025.054-.045.087-.06.033-.015.069-.022.108-.022.043 0 .083.009.119.027.035.019.066.047.093.084v-.302h.068V0H.537v-.091C.508-.056.475-.029.44-.013.404.005.365.013.323.013.284.013.248.006.215-.01.182-.024.153-.045.129-.071.104-.096.085-.126.072-.16.058-.193.051-.229.051-.267Zm.279.218c.027 0 .054-.005.079-.015.025-.01.048-.024.068-.043.019-.018.035-.04.047-.067.011-.027.017-.056.017-.089 0-.031-.005-.059-.016-.086C.514-.375.5-.398.481-.417.462-.436.439-.452.414-.463.389-.474.361-.479.331-.479c-.031 0-.059.006-.084.017C.221-.45.199-.434.18-.415c-.019.02-.033.043-.043.068-.011.026-.016.053-.016.082 0 .029.005.056.016.082.011.026.025.049.044.069.019.02.041.036.066.047.025.012.053.018.083.018Z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(488.71612761 521.8022953) scale(235.3092)"/>
|
||||
<path d="m.034-.062.043-.049c.017.019.035.034.054.044.018.01.037.015.057.015.013 0 .026-.002.038-.007.011-.004.021-.01.031-.018.009-.008.016-.017.021-.028.005-.011.008-.022.008-.035 0-.019-.005-.034-.014-.047C.263-.199.248-.21.229-.221.205-.234.183-.247.162-.259.14-.271.122-.284.107-.298.092-.311.08-.327.071-.344.062-.361.058-.381.058-.404c0-.021.004-.04.012-.058.007-.016.018-.031.031-.044.013-.013.028-.022.046-.029.018-.007.037-.01.057-.01.029 0 .056.006.079.019s.045.031.068.053l-.044.045C.291-.443.275-.456.258-.465.241-.474.221-.479.2-.479c-.022 0-.041.007-.056.02C.128-.445.12-.428.12-.408c0 .019.006.035.017.048.011.013.027.026.048.037.027.015.05.028.071.04.021.013.038.026.052.039.014.013.025.028.032.044.007.016.011.035.011.057 0 .021-.004.041-.011.059-.008.019-.019.036-.033.05-.014.015-.031.026-.05.035C.237.01.215.014.191.014c-.03 0-.059-.006-.086-.02C.077-.019.053-.037.034-.062Z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(649.90292961 521.8022953) scale(235.3092)"/>
|
||||
<path d="M.051-.266c0-.04.007-.077.022-.111.014-.034.034-.063.059-.089.025-.025.054-.044.089-.058.035-.014.072-.021.113-.021.051 0 .098.01.139.03.041.021.075.049.1.085l-.05.043C.498-.418.47-.441.439-.456.408-.471.372-.479.331-.479c-.03 0-.058.005-.083.016C.222-.452.2-.436.181-.418.162-.399.148-.376.137-.35c-.011.026-.016.054-.016.084 0 .031.005.06.016.086.011.027.025.049.044.068.019.019.041.034.067.044.025.011.053.016.084.016.077 0 .141-.03.191-.09l.051.04c-.028.036-.062.064-.103.085C.43.004.384.014.332.014.291.014.254.007.219-.008.184-.022.155-.042.13-.067.105-.092.086-.121.072-.156.058-.19.051-.227.051-.266Z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(741.20289921 521.8022953) scale(235.3092)"/>
|
||||
<path d="M.051-.267c0-.038.007-.074.021-.108.014-.033.033-.063.058-.088.025-.025.054-.045.087-.06.033-.015.069-.022.108-.022.043 0 .083.009.119.027.035.019.066.047.093.084v-.097h.067V0H.537v-.091C.508-.056.475-.029.44-.013.404.005.365.013.323.013.284.013.248.006.215-.01.182-.024.153-.045.129-.071.104-.096.085-.126.072-.16.058-.193.051-.229.051-.267Zm.279.218c.027 0 .054-.005.079-.015.025-.01.048-.024.068-.043.019-.018.035-.04.047-.067.012-.027.018-.056.018-.089 0-.031-.005-.059-.016-.086C.515-.375.501-.398.482-.417.462-.436.44-.452.415-.463.389-.474.361-.479.331-.479c-.031 0-.059.006-.084.017C.221-.45.199-.434.18-.415c-.019.02-.033.043-.043.068-.011.026-.016.053-.016.082 0 .029.005.056.016.082.011.026.025.049.044.069.019.02.041.036.066.047.025.012.053.018.083.018Z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(884.27089281 521.8022953) scale(235.3092)"/>
|
||||
<path d="M.066-.736h.068V0H.066z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(1045.22238561 521.8022953) scale(235.3092)"/>
|
||||
<path d="M.051-.264c0-.036.007-.071.02-.105.013-.034.031-.064.055-.09.023-.026.052-.047.086-.063.033-.015.071-.023.112-.023.039 0 .076.007.109.021.033.014.062.033.087.058.025.025.044.054.058.088.014.035.021.072.021.113v.005H.121c.001.031.007.059.018.084.01.025.024.047.042.065.018.019.04.033.065.043.025.01.052.015.082.015.026 0 .049-.003.069-.01.02-.007.038-.016.054-.028C.466-.102.48-.115.492-.13c.011-.015.022-.03.032-.046l.057.03C.556-.097.522-.058.48-.03.437-.001.387.013.328.013.284.013.245.006.21-.01.175-.024.146-.045.123-.07.1-.095.082-.125.07-.159.057-.192.051-.227.051-.264ZM.128-.32h.396C.51-.375.485-.416.449-.441.412-.466.371-.479.325-.479c-.048 0-.089.013-.123.039-.034.026-.059.066-.074.12Z" style="fill: #8d8d8d; fill-rule: nonzero" transform="translate(1092.28422561 521.8022953) scale(235.3092)"/>
|
||||
<circle cx="141.023" cy="338.36" r="117.472" style="fill: #f8b5cb" transform="matrix(.581302 0 0 .58613 40.06479894 12.59842153)"/>
|
||||
<circle cx="352.014" cy="268.302" r="33.095" style="fill: #a2a2a2" transform="matrix(.59308 0 0 .58289 32.39345942 21.2386)"/>
|
||||
<circle cx="352.014" cy="268.302" r="33.095" style="fill: #a2a2a2" transform="matrix(.59308 0 0 .58289 32.39345942 88.80371146)"/>
|
||||
<circle cx="352.014" cy="268.302" r="33.095" style="fill: #a2a2a2" transform="matrix(.59308 0 0 .58289 120.7528627 88.80371146)"/>
|
||||
<circle cx="352.014" cy="268.302" r="33.095" style="fill: #a2a2a2" transform="matrix(.59308 0 0 .58289 120.99825939 21.2386)"/>
|
||||
<circle cx="805.557" cy="336.915" r="118.199" style="fill: #8d8d8d" transform="matrix(.5782 0 0 .58289 36.19871106 15.26642564)"/>
|
||||
<circle cx="805.557" cy="336.915" r="118.199" style="fill: #8d8d8d" transform="matrix(.5782 0 0 .58289 183.24041937 15.26642564)"/>
|
||||
<path d="M680.282 124.808h-68.093v390.325h68.081v-28.23H640V153.228h40.282v-28.42Z" style="fill: #303030" transform="translate(34.2345 21.2386) scale(.58289)"/>
|
||||
<path d="M680.282 124.808h-68.093v390.325h68.081v-28.23H640V153.228h40.282v-28.42Z" style="fill: #303030" transform="matrix(-.58289 0 0 .58289 1116.7719791 21.2386)"/>
|
||||
</svg>`)
|
||||
}
|
||||
|
||||
// checkboxIcon returns the success checkbox SVG icon as raw HTML
|
||||
// checkboxIcon returns the success checkbox SVG icon as raw HTML.
|
||||
func checkboxIcon() elem.Node {
|
||||
return elem.Raw(`<svg id="checkbox" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 512 512">
|
||||
return elem.Raw(`<svg id="checkbox" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 512 512">
|
||||
<path d="M256 32C132.3 32 32 132.3 32 256s100.3 224 224 224 224-100.3 224-224S379.7 32 256 32zm114.9 149.1L231.8 359.6c-1.1 1.1-2.9 3.5-5.1 3.5-2.3 0-3.8-1.6-5.1-2.9-1.3-1.3-78.9-75.9-78.9-75.9l-1.5-1.5c-.6-.9-1.1-2-1.1-3.2 0-1.2.5-2.3 1.1-3.2.4-.4.7-.7 1.1-1.2 7.7-8.1 23.3-24.5 24.3-25.5 1.3-1.3 2.4-3 4.8-3 2.5 0 4.1 2.1 5.3 3.3 1.2 1.2 45 43.3 45 43.3l111.3-143c1-.8 2.2-1.4 3.5-1.4 1.3 0 2.5.5 3.5 1.3l30.6 24.1c.8 1 1.3 2.2 1.3 3.5.1 1.3-.4 2.4-1 3.3z"></path>
|
||||
</svg>`)
|
||||
}
|
||||
|
||||
// externalLinkIcon returns the external link SVG icon as raw HTML
|
||||
func externalLinkIcon() elem.Node {
|
||||
return elem.Raw(`<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.307 1H11.5a.5.5 0 1 1 0-1h3a.499.499 0 0 1 .5.65V3.5a.5.5 0 1 1-1 0V1.72l-1.793 1.774a.5.5 0 0 1-.713-.701L13.307 1zM12 14V8a.5.5 0 1 1 1 0v6.5a.5.5 0 0 1-.5.5H.563a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 .5-.5H8a.5.5 0 0 1 0 1H1v12h11zM4 6a.5.5 0 0 1 0-1h3a.5.5 0 0 1 0 1H4zm0 2.5a.5.5 0 0 1 0-1h5a.5.5 0 0 1 0 1H4zM4 11a.5.5 0 1 1 0-1h5a.5.5 0 1 1 0 1H4z"/>
|
||||
</svg>`)
|
||||
}
|
||||
|
||||
// oidcCallbackStyles returns the CSS styles for the OIDC callback page
|
||||
func oidcCallbackStyles() *elem.Element {
|
||||
return elem.Style(nil, elem.Text(`
|
||||
body {
|
||||
font-size: 14px;
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
"Roboto",
|
||||
"Oxygen",
|
||||
"Ubuntu",
|
||||
"Cantarell",
|
||||
"Fira Sans",
|
||||
"Droid Sans",
|
||||
"Helvetica Neue",
|
||||
sans-serif;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: #fdfdfe;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 70vh;
|
||||
}
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: -20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.message {
|
||||
display: flex;
|
||||
min-width: 40vw;
|
||||
background: #fafdfa;
|
||||
border: 1px solid #c6e9c9;
|
||||
margin-bottom: 12px;
|
||||
padding: 12px 16px 16px 12px;
|
||||
position: relative;
|
||||
border-radius: 2px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.message #checkbox {
|
||||
fill: #2eb039;
|
||||
}
|
||||
|
||||
.message .message-title {
|
||||
color: #1e7125;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.message .message-body {
|
||||
border: 0;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.message p {
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #17421b;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
margin: 8px 0;
|
||||
color: #1563ff;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
a svg {
|
||||
fill: currentcolor;
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 17.5px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h1 + p {
|
||||
margin: 8px 0 16px 0;
|
||||
}
|
||||
`))
|
||||
}
|
||||
|
||||
// OIDCCallback renders the OIDC authentication success callback page
|
||||
// OIDCCallback renders the OIDC authentication success callback page.
|
||||
func OIDCCallback(user, verb string) *elem.Element {
|
||||
return elem.Html(attrs.Props{attrs.Lang: "en"},
|
||||
elem.Head(nil,
|
||||
elem.Meta(attrs.Props{attrs.Charset: "UTF-8"}),
|
||||
elem.Meta(attrs.Props{
|
||||
attrs.HTTPequiv: "X-UA-Compatible",
|
||||
attrs.Content: "IE=edge",
|
||||
}),
|
||||
elem.Meta(attrs.Props{
|
||||
attrs.Name: "viewport",
|
||||
attrs.Content: "width=device-width, initial-scale=1.0",
|
||||
}),
|
||||
elem.Title(nil, elem.Text("Headscale Authentication Succeeded")),
|
||||
oidcCallbackStyles(),
|
||||
// Success message box
|
||||
successBox := elem.Div(attrs.Props{
|
||||
attrs.Style: styles.Props{
|
||||
styles.Display: "flex",
|
||||
styles.AlignItems: "center",
|
||||
styles.Gap: spaceM,
|
||||
styles.Padding: spaceL,
|
||||
styles.BackgroundColor: colorSuccessLight,
|
||||
styles.Border: "1px solid " + colorSuccess,
|
||||
styles.BorderRadius: "0.5rem",
|
||||
styles.MarginBottom: spaceXL,
|
||||
}.ToInline(),
|
||||
},
|
||||
checkboxIcon(),
|
||||
elem.Div(nil,
|
||||
elem.Strong(attrs.Props{
|
||||
attrs.Style: styles.Props{
|
||||
styles.Display: "block",
|
||||
styles.Color: colorSuccess,
|
||||
styles.FontSize: fontSizeH3,
|
||||
styles.MarginBottom: spaceXS,
|
||||
}.ToInline(),
|
||||
}, elem.Text("Signed in successfully")),
|
||||
elem.P(attrs.Props{
|
||||
attrs.Style: styles.Props{
|
||||
styles.Margin: "0",
|
||||
styles.Color: colorTextPrimary,
|
||||
styles.FontSize: fontSizeBase,
|
||||
}.ToInline(),
|
||||
}, elem.Text(verb), elem.Text(" as "), elem.Strong(nil, elem.Text(user)), elem.Text(". You can now close this window.")),
|
||||
),
|
||||
elem.Body(attrs.Props{"translate": "no"},
|
||||
elem.Div(attrs.Props{attrs.Class: "container"},
|
||||
elem.Div(nil,
|
||||
headscaleLogo(),
|
||||
elem.Div(attrs.Props{attrs.Class: "message is-success"},
|
||||
checkboxIcon(),
|
||||
elem.Div(attrs.Props{attrs.Class: "message-content"},
|
||||
elem.Div(attrs.Props{attrs.Class: "message-title"},
|
||||
elem.Text("Signed in via your OIDC provider"),
|
||||
),
|
||||
elem.P(attrs.Props{attrs.Class: "message-body"},
|
||||
elem.Text(verb),
|
||||
elem.Text(" as "),
|
||||
elem.Text(user),
|
||||
elem.Text(", you can now close this window."),
|
||||
),
|
||||
),
|
||||
),
|
||||
elem.Hr(nil),
|
||||
elem.H1(nil, elem.Text("Not sure how to get started?")),
|
||||
elem.P(attrs.Props{attrs.Class: "learn"},
|
||||
elem.Text("Check out beginner and advanced guides on, or read more in the documentation."),
|
||||
),
|
||||
elem.A(attrs.Props{
|
||||
attrs.Href: "https://github.com/juanfont/headscale/tree/main/docs",
|
||||
attrs.Rel: "noreferrer noopener",
|
||||
attrs.Target: "_blank",
|
||||
},
|
||||
elem.Span(attrs.Props{attrs.Class: "icon"},
|
||||
externalLinkIcon(),
|
||||
),
|
||||
elem.Text("View the headscale documentation"),
|
||||
),
|
||||
elem.A(attrs.Props{
|
||||
attrs.Href: "https://tailscale.com/kb/",
|
||||
attrs.Rel: "noreferrer noopener",
|
||||
attrs.Target: "_blank",
|
||||
},
|
||||
elem.Span(attrs.Props{attrs.Class: "icon"},
|
||||
externalLinkIcon(),
|
||||
),
|
||||
elem.Text("View the tailscale documentation"),
|
||||
),
|
||||
)
|
||||
|
||||
return HtmlStructure(
|
||||
elem.Title(nil, elem.Text("Headscale Authentication Succeeded")),
|
||||
mdTypesetBody(
|
||||
headscaleLogo(),
|
||||
successBox,
|
||||
H2(elem.Text("Getting started")),
|
||||
P(elem.Text("Check out the documentation to learn more about headscale and Tailscale:")),
|
||||
Ul(
|
||||
elem.Li(nil,
|
||||
externalLink("https://github.com/juanfont/headscale/tree/main/docs", "Headscale documentation"),
|
||||
),
|
||||
elem.Li(nil,
|
||||
externalLink("https://tailscale.com/kb/", "Tailscale knowledge base"),
|
||||
),
|
||||
),
|
||||
pageFooter(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user