mirror of
https://github.com/rjNemo/auth
synced 2026-06-06 00:16:40 +00:00
feat: unify auth templates
This commit is contained in:
parent
abd0642edd
commit
c02501329a
7 changed files with 490 additions and 172 deletions
|
|
@ -32,6 +32,7 @@ type Server struct {
|
|||
func New(cfg config.Config, logger *slog.Logger) (*Server, error) {
|
||||
tmpl, err := template.ParseFS(
|
||||
web.Templates,
|
||||
"templates/auth_base.html",
|
||||
"templates/login.html",
|
||||
"templates/dashboard.html",
|
||||
"templates/signup.html",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ func (s *Server) render(w http.ResponseWriter, name string, data any) {
|
|||
|
||||
// PageData contains fields shared by the templates for now.
|
||||
type PageData struct {
|
||||
Title string
|
||||
View string
|
||||
Email string
|
||||
Error string
|
||||
Info string
|
||||
|
|
@ -26,17 +28,29 @@ type PageData struct {
|
|||
}
|
||||
|
||||
func newLoginData(email, errMsg, token string) PageData {
|
||||
return PageData{Email: email, Error: errMsg, CSRFToken: token}
|
||||
return PageData{Title: "Sign in · Auth Demo", View: "login", Email: email, Error: errMsg, CSRFToken: token}
|
||||
}
|
||||
|
||||
func newUnauthorizedData(errMsg, token string) PageData {
|
||||
return PageData{Error: errMsg, CSRFToken: token}
|
||||
return PageData{
|
||||
Title: "Access denied · Auth Demo",
|
||||
View: "unauthorized",
|
||||
Error: errMsg,
|
||||
CSRFToken: token,
|
||||
}
|
||||
}
|
||||
|
||||
func newDashboardData(email, token, createdAt, createdAtISO string) PageData {
|
||||
return PageData{Email: email, CSRFToken: token, CreatedAt: createdAt, CreatedAtISO: createdAtISO}
|
||||
return PageData{
|
||||
Title: "Dashboard · Auth Demo",
|
||||
View: "dashboard",
|
||||
Email: email,
|
||||
CSRFToken: token,
|
||||
CreatedAt: createdAt,
|
||||
CreatedAtISO: createdAtISO,
|
||||
}
|
||||
}
|
||||
|
||||
func newSignupData(email, errMsg, token string) PageData {
|
||||
return PageData{Email: email, Error: errMsg, CSRFToken: token}
|
||||
return PageData{Title: "Create account · Auth Demo", View: "signup", Email: email, Error: errMsg, CSRFToken: token}
|
||||
}
|
||||
|
|
|
|||
272
web/templates/auth_base.html
Normal file
272
web/templates/auth_base.html
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
{{define "auth_base"}}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{{if .Title}}{{.Title}}{{else}}Auth Demo{{end}}</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
|
||||
/>
|
||||
<style>
|
||||
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
|
||||
|
||||
:root {
|
||||
--pico-font-family: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
|
||||
--pico-background-color: #f0f1f6;
|
||||
--pico-color: #1f2033;
|
||||
--pico-muted-color: #6c6f7f;
|
||||
--pico-card-background-color: #ffffff;
|
||||
--pico-border-radius: 1.75rem;
|
||||
--pico-form-element-border-radius: 0.85rem;
|
||||
--pico-primary: #6b3df0;
|
||||
--pico-primary-hover: #5630c7;
|
||||
--pico-primary-focus: rgba(107, 61, 240, 0.25);
|
||||
--pico-primary-inverse: #ffffff;
|
||||
--pico-form-element-active-border-color: #6b3df0;
|
||||
--pico-shadow: 0 25px 45px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--pico-background-color);
|
||||
}
|
||||
|
||||
.auth-wrapper {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: clamp(1.5rem, 4vw, 3rem);
|
||||
}
|
||||
|
||||
.auth-card {
|
||||
width: min(960px, 100%);
|
||||
background: var(--pico-card-background-color);
|
||||
border-radius: var(--pico-border-radius);
|
||||
box-shadow: var(--pico-shadow);
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(240px, 1fr) minmax(320px, 1.2fr);
|
||||
}
|
||||
|
||||
.auth-visual {
|
||||
color: var(--pico-primary-inverse);
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(19, 27, 52, 0.35),
|
||||
rgba(19, 27, 52, 0.75)
|
||||
),
|
||||
url("https://images.unsplash.com/photo-1545239351-1141bd82e8a6?auto=format&fit=crop&w=900&q=80")
|
||||
center/cover no-repeat;
|
||||
padding: clamp(2rem, 4vw, 3rem);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.auth-logo {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.auth-logo-mark {
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgba(255, 255, 255, 0.45);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.auth-quote blockquote {
|
||||
margin: 0;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.auth-quote cite {
|
||||
display: block;
|
||||
font-style: normal;
|
||||
font-size: 0.85rem;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
margin-top: 0.85rem;
|
||||
}
|
||||
|
||||
.auth-content {
|
||||
padding: clamp(2.25rem, 5vw, 3.25rem);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.75rem;
|
||||
}
|
||||
|
||||
.auth-heading h1 {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: clamp(1.9rem, 3vw, 2.35rem);
|
||||
}
|
||||
|
||||
.auth-heading p {
|
||||
margin: 0;
|
||||
color: var(--pico-muted-color);
|
||||
}
|
||||
|
||||
.auth-note {
|
||||
border-radius: var(--pico-form-element-border-radius);
|
||||
padding: 1rem 1.1rem;
|
||||
background: color-mix(in srgb, var(--pico-primary) 12%, #ffffff);
|
||||
border: 1px dashed color-mix(in srgb, var(--pico-primary) 45%, transparent);
|
||||
font-size: 0.95rem;
|
||||
color: var(--pico-muted-color);
|
||||
}
|
||||
|
||||
.auth-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.auth-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.auth-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
color: var(--pico-muted-color);
|
||||
}
|
||||
|
||||
.auth-toggle input[type="checkbox"] {
|
||||
accent-color: var(--pico-primary);
|
||||
}
|
||||
|
||||
.auth-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.auth-divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--pico-muted-color);
|
||||
}
|
||||
|
||||
.auth-divider::before,
|
||||
.auth-divider::after {
|
||||
content: "";
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: color-mix(in srgb, var(--pico-muted-color) 25%, transparent);
|
||||
}
|
||||
|
||||
.auth-google {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.auth-google svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.auth-footer {
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
color: var(--pico-muted-color);
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
.auth-card {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.auth-visual {
|
||||
min-height: 260px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="auth-wrapper">
|
||||
<article class="auth-card">
|
||||
<section class="auth-visual" aria-label="Product testimonial">
|
||||
<header class="auth-logo">
|
||||
<span class="auth-logo-mark">N</span>
|
||||
Nucleus
|
||||
</header>
|
||||
<div class="auth-quote">
|
||||
<blockquote>“Simply all the tools that my team and I need.”</blockquote>
|
||||
<cite>Karen Yue · Director of Digital Marketing Technology</cite>
|
||||
</div>
|
||||
</section>
|
||||
<section class="auth-content">
|
||||
{{if eq .View "login"}}
|
||||
{{template "login_content" .}}
|
||||
{{else if eq .View "signup"}}
|
||||
{{template "signup_content" .}}
|
||||
{{else if eq .View "dashboard"}}
|
||||
{{template "dashboard_content" .}}
|
||||
{{else if eq .View "unauthorized"}}
|
||||
{{template "unauthorized_content" .}}
|
||||
{{else}}
|
||||
{{template "auth_default_content" .}}
|
||||
{{end}}
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
|
||||
{{define "auth_default_content"}}
|
||||
<div class="auth-heading">
|
||||
<h1>Authentication</h1>
|
||||
<p>Pick an auth flow to continue.</p>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "dashboard_content"}}
|
||||
<div class="auth-heading">
|
||||
<h1>Welcome back</h1>
|
||||
<p>You're signed in as <strong>{{.Email}}</strong>.</p>
|
||||
</div>
|
||||
<article>
|
||||
{{if .CreatedAt}}
|
||||
<p>
|
||||
Member since
|
||||
<time datetime="{{.CreatedAtISO}}">{{.CreatedAt}}</time>.
|
||||
</p>
|
||||
{{end}}
|
||||
<p>This dashboard will grow alongside the authentication features.</p>
|
||||
</article>
|
||||
<form method="post" action="/logout" class="auth-actions">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRFToken}}" />
|
||||
<button type="submit" class="secondary">Sign out</button>
|
||||
</form>
|
||||
{{end}}
|
||||
|
||||
{{define "unauthorized_content"}}
|
||||
<div class="auth-heading">
|
||||
<h1>Access denied</h1>
|
||||
<p>{{if .Error}}{{.Error}}{{else}}You do not have permission to view that page.{{end}}</p>
|
||||
</div>
|
||||
<p class="auth-footer">
|
||||
<a href="/" role="button">Back to safety</a>
|
||||
</p>
|
||||
{{end}}
|
||||
|
|
@ -1,35 +1,3 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Dashboard</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<h1>Welcome</h1>
|
||||
<article>
|
||||
<p>You are signed in as <strong>{{.Email}}</strong>.</p>
|
||||
{{if .CreatedAt}}
|
||||
<p>
|
||||
Member since
|
||||
<time datetime="{{.CreatedAtISO}}">{{.CreatedAt}}</time>.
|
||||
</p>
|
||||
{{end}}
|
||||
<p>
|
||||
This placeholder dashboard will evolve as we flesh out the auth flow.
|
||||
</p>
|
||||
<footer>
|
||||
<form method="post" action="/logout">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRFToken}}" />
|
||||
<button type="submit" class="secondary">Sign out</button>
|
||||
</form>
|
||||
</footer>
|
||||
</article>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{define "dashboard.html"}}
|
||||
{{template "auth_base" .}}
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,89 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Auth Demo</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<h1>Sign in</h1>
|
||||
<p>Authenticate with the demo credentials below to view the dashboard.</p>
|
||||
<article>
|
||||
<header>Demo account</header>
|
||||
<p>
|
||||
<strong>Email:</strong> user@example.com<br /><strong>
|
||||
Password:
|
||||
</strong>
|
||||
Password123
|
||||
</p>
|
||||
</article>
|
||||
{{if .Error}}
|
||||
<article class="secondary">
|
||||
<strong>Unable to sign in:</strong> {{.Error}}
|
||||
</article>
|
||||
{{end}}
|
||||
<form method="post" action="/login">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRFToken}}" />
|
||||
<label for="email">Email</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
autofocus
|
||||
value="{{.Email}}"
|
||||
/>
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
required
|
||||
pattern="(?=.*[A-Z])(?=.*\d).{8,}"
|
||||
title="At least 8 characters including one uppercase letter and one number"
|
||||
/>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<p>
|
||||
Need an account?
|
||||
<a href="/signup">Create one now</a>.
|
||||
</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{define "login.html"}}
|
||||
{{template "auth_base" .}}
|
||||
{{end}}
|
||||
|
||||
{{define "login_content"}}
|
||||
<div class="auth-heading">
|
||||
<h1>Welcome back to Nucleus</h1>
|
||||
<p>Build your design system effortlessly with our powerful component library.</p>
|
||||
</div>
|
||||
<div class="auth-note" role="note">
|
||||
<strong>Demo account access</strong><br />
|
||||
Email: user@example.com · Password: Password123
|
||||
</div>
|
||||
{{if .Error}}
|
||||
<article class="contrast" role="alert">
|
||||
<header>Unable to sign in</header>
|
||||
<p>{{.Error}}</p>
|
||||
</article>
|
||||
{{end}}
|
||||
<form method="post" action="/login" class="auth-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRFToken}}" />
|
||||
<label for="email">
|
||||
Email
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
autofocus
|
||||
value="{{.Email}}"
|
||||
/>
|
||||
</label>
|
||||
<label for="password">
|
||||
Password
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Your password"
|
||||
required
|
||||
pattern="(?=.*[A-Z])(?=.*\d).{8,}"
|
||||
title="At least 8 characters including one uppercase letter and one number"
|
||||
/>
|
||||
</label>
|
||||
<div class="auth-meta">
|
||||
<a href="#">Forgot password?</a>
|
||||
<label class="auth-toggle">
|
||||
<input type="checkbox" name="remember" />
|
||||
Remember me
|
||||
</label>
|
||||
</div>
|
||||
<div class="auth-actions">
|
||||
<button type="submit" class="primary">Log in</button>
|
||||
<div class="auth-divider">or</div>
|
||||
<button type="button" class="secondary outline auth-google">
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M21.6 12.23c0-.74-.06-1.28-.19-1.84H12v3.34h5.52c-.11.83-.72 2.09-2.08 2.94l-.02.11 3.02 2.34.21.02c1.95-1.8 3.05-4.45 3.05-7.25z"
|
||||
fill="#4285F4"
|
||||
/>
|
||||
<path
|
||||
d="M12 22c2.7 0 4.97-.89 6.63-2.41l-3.16-2.45c-.84.56-1.96.95-3.47.95-2.66 0-4.92-1.8-5.72-4.29H3.07v2.52C4.71 19.98 8.08 22 12 22z"
|
||||
fill="#34A853"
|
||||
/>
|
||||
<path
|
||||
d="M6.28 13.8a5.95 5.95 0 010-3.6V7.68H3.07a9.96 9.96 0 000 8.64l3.21-2.52z"
|
||||
fill="#FBBC05"
|
||||
/>
|
||||
<path
|
||||
d="M12 5.91c1.87 0 3.13.81 3.85 1.49l2.81-2.74C16.96 3.13 14.7 2 12 2 8.08 2 4.71 4.02 3.07 7.32l3.21 2.52C7.08 7.71 9.34 5.91 12 5.91z"
|
||||
fill="#EA4335"
|
||||
/>
|
||||
</svg>
|
||||
Continue with Google
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<p class="auth-footer">
|
||||
Don't have an account? <a href="/signup">Sign up</a>
|
||||
</p>
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,104 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Create Account</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<h1>Sign up</h1>
|
||||
<p>Provide your email and a strong password to create an account.</p>
|
||||
{{if .Error}}
|
||||
<article class="secondary">
|
||||
<strong>Unable to sign up:</strong> {{.Error}}
|
||||
</article>
|
||||
{{end}}
|
||||
<form method="post" action="/signup">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRFToken}}" />
|
||||
<label for="email">Email</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
autofocus
|
||||
value="{{.Email}}"
|
||||
/>
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Choose a password"
|
||||
required
|
||||
pattern="(?=.*[A-Z])(?=.*\d).{8,}"
|
||||
title="At least 8 characters including one uppercase letter and one number"
|
||||
/>
|
||||
<button type="submit">Create account</button>
|
||||
</form>
|
||||
<p>
|
||||
Already registered?
|
||||
<a href="/">Return to sign in</a>.
|
||||
</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{define "signup.html"}}
|
||||
{{template "auth_base" .}}
|
||||
{{end}}
|
||||
|
||||
{{define "signup_content"}}
|
||||
<div class="auth-heading">
|
||||
<h1>Create your account</h1>
|
||||
<p>Join Nucleus UI and start designing with ease.</p>
|
||||
</div>
|
||||
{{if .Info}}
|
||||
<article class="secondary" role="status">
|
||||
<header>Heads-up</header>
|
||||
<p>{{.Info}}</p>
|
||||
</article>
|
||||
{{end}}
|
||||
{{if .Error}}
|
||||
<article class="contrast" role="alert">
|
||||
<header>Unable to sign up</header>
|
||||
<p>{{.Error}}</p>
|
||||
</article>
|
||||
{{end}}
|
||||
<form method="post" action="/signup" class="auth-form">
|
||||
<input type="hidden" name="_csrf" value="{{.CSRFToken}}" />
|
||||
<label for="name">
|
||||
Name
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Your name"
|
||||
autocomplete="name"
|
||||
/>
|
||||
</label>
|
||||
<label for="email">
|
||||
Email
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
autocomplete="email"
|
||||
value="{{.Email}}"
|
||||
/>
|
||||
</label>
|
||||
<label for="password">
|
||||
Password
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Choose a password"
|
||||
required
|
||||
pattern="(?=.*[A-Z])(?=.*\d).{8,}"
|
||||
title="At least 8 characters including one uppercase letter and one number"
|
||||
/>
|
||||
</label>
|
||||
<label for="password_confirm">
|
||||
Confirm password
|
||||
<input
|
||||
type="password"
|
||||
id="password_confirm"
|
||||
name="password_confirm"
|
||||
placeholder="Re-type your password"
|
||||
required
|
||||
/>
|
||||
</label>
|
||||
<div class="auth-actions">
|
||||
<button type="submit" class="primary">Create account</button>
|
||||
<div class="auth-divider">or</div>
|
||||
<button type="button" class="secondary outline auth-google">
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M21.6 12.23c0-.74-.06-1.28-.19-1.84H12v3.34h5.52c-.11.83-.72 2.09-2.08 2.94l-.02.11 3.02 2.34.21.02c1.95-1.8 3.05-4.45 3.05-7.25z"
|
||||
fill="#4285F4"
|
||||
/>
|
||||
<path
|
||||
d="M12 22c2.7 0 4.97-.89 6.63-2.41l-3.16-2.45c-.84.56-1.96.95-3.47.95-2.66 0-4.92-1.8-5.72-4.29H3.07v2.52C4.71 19.98 8.08 22 12 22z"
|
||||
fill="#34A853"
|
||||
/>
|
||||
<path
|
||||
d="M6.28 13.8a5.95 5.95 0 010-3.6V7.68H3.07a9.96 9.96 0 000 8.64l3.21-2.52z"
|
||||
fill="#FBBC05"
|
||||
/>
|
||||
<path
|
||||
d="M12 5.91c1.87 0 3.13.81 3.85 1.49l2.81-2.74C16.96 3.13 14.7 2 12 2 8.08 2 4.71 4.02 3.07 7.32l3.21 2.52C7.08 7.71 9.34 5.91 12 5.91z"
|
||||
fill="#EA4335"
|
||||
/>
|
||||
</svg>
|
||||
Sign up with Google
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<p class="auth-footer">
|
||||
Have an account? <a href="/">Log in</a>
|
||||
</p>
|
||||
{{end}}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,3 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Unauthorized</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<h1>Unauthorized</h1>
|
||||
<p>
|
||||
{{if .Error}}{{.Error}}{{else}}You do not have permission to view that
|
||||
page.{{end}}
|
||||
</p>
|
||||
<a href="/" role="button">Back to safety</a>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{define "unauthorized.html"}}
|
||||
{{template "auth_base" .}}
|
||||
{{end}}
|
||||
|
|
|
|||
Loading…
Reference in a new issue