feat(login-page): full HF logo, primary title, pill CTA, refined layout
Browse files- Inline the complete official Hugging Face logo SVG (face + both hugging
hands), fixing the previously truncated mark in the button
- Move the title to primary color and bump it to a fluid clamp size with
Apple-grade letter-spacing
- Replace the outlined CTA with a pill-shaped primary button: vertical
gradient fill, layered inset highlights, soft elevation, 1px lift on
hover with deeper shadow, slightly tighter letter-spacing
- Drop the "after signing in, refresh this page" hint since the OAuth flow
redirects automatically
- Add a soft radial primary tint on the page background and a discreet
wordmark below the CTA for brand presence
- Use the SF / Source Sans Pro stack with antialiasing tuned for both light
and dark modes
- Simplify renderLoginPage: hint slot removed, callers now only pass title
and description
Made-with: Cursor
- backend/src/create-app.ts +102 -57
|
@@ -21,34 +21,32 @@ export { debouncedSave, resetSaveTimers, resetPublishedRestored } from "./persis
|
|
| 21 |
const DEFAULT_DOC_NAME = "default";
|
| 22 |
|
| 23 |
/**
|
| 24 |
-
*
|
| 25 |
-
*
|
|
|
|
|
|
|
| 26 |
*/
|
| 27 |
-
const HF_LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95 88" width="
|
| 28 |
<path fill="#FFD21E" d="M47.21 76.5a34.75 34.75 0 1 0 0-69.5 34.75 34.75 0 0 0 0 69.5Z"/>
|
| 29 |
<path fill="#FF9D0B" d="M81.96 41.75a34.75 34.75 0 1 0-69.5 0 34.75 34.75 0 0 0 69.5 0Zm-73.5 0a38.75 38.75 0 1 1 77.5 0 38.75 38.75 0 0 1-77.5 0Z"/>
|
| 30 |
<path fill="#3A3B45" d="M58.5 32.3c1.28.44 1.78 3.06 3.07 2.38a5 5 0 1 0-6.76-2.07c.61 1.15 2.55-.72 3.7-.32ZM34.95 32.3c-1.28.44-1.79 3.06-3.07 2.38a5 5 0 1 1 6.76-2.07c-.61 1.15-2.56-.72-3.7-.32Z"/>
|
| 31 |
<path fill="#FF323D" d="M46.96 56.29c9.83 0 13-8.76 13-13.26 0-2.34-1.57-1.6-4.09-.36-2.33 1.15-5.46 2.74-8.9 2.74-7.19 0-13-6.88-13-2.38s3.16 13.26 13 13.26Z"/>
|
| 32 |
<path fill="#3A3B45" fill-rule="evenodd" d="M39.43 54a8.7 8.7 0 0 1 5.3-4.49c.4-.12.81.57 1.24 1.28.4.68.82 1.37 1.24 1.37.45 0 .9-.68 1.33-1.35.45-.7.89-1.38 1.32-1.25a8.61 8.61 0 0 1 5 4.17c3.73-2.94 5.1-7.74 5.1-10.7 0-2.34-1.57-1.6-4.09-.36l-.14.07c-2.31 1.15-5.39 2.67-8.77 2.67s-6.45-1.52-8.77-2.67c-2.6-1.29-4.23-2.1-4.23.29 0 3.05 1.46 8.06 5.47 10.97Z" clip-rule="evenodd"/>
|
| 33 |
<path fill="#FF9D0B" d="M70.71 37a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5ZM24.21 37a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5Z"/>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
</svg>`;
|
| 35 |
|
| 36 |
interface LoginPageOptions {
|
| 37 |
title: string;
|
| 38 |
description: string;
|
| 39 |
-
/** Optional secondary line shown below the button (e.g. "after signing in, refresh"). */
|
| 40 |
-
hint?: string;
|
| 41 |
}
|
| 42 |
|
| 43 |
-
function renderLoginPage({ title, description
|
| 44 |
const safeTitle = escapeHtml(title);
|
| 45 |
const safeDescription = escapeHtml(description);
|
| 46 |
-
const hintHtml = hint
|
| 47 |
-
? `<p class="login__hint">${escapeHtml(hint).replace(
|
| 48 |
-
/\{refresh\}/g,
|
| 49 |
-
`<a class="login__hint-link" href="/editor">refresh this page</a>`,
|
| 50 |
-
)}</p>`
|
| 51 |
-
: "";
|
| 52 |
|
| 53 |
return `<!DOCTYPE html>
|
| 54 |
<html lang="en">
|
|
@@ -59,20 +57,39 @@ function renderLoginPage({ title, description, hint }: LoginPageOptions): string
|
|
| 59 |
<style>
|
| 60 |
:root {
|
| 61 |
--primary-color: oklch(0.75 0.12 47);
|
| 62 |
-
--primary-color-hover: oklch(from var(--primary-color) calc(l - 0.
|
| 63 |
-
--
|
| 64 |
-
--
|
| 65 |
-
--
|
| 66 |
-
--
|
| 67 |
-
--
|
| 68 |
-
--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
}
|
| 70 |
@media (prefers-color-scheme: dark) {
|
| 71 |
:root {
|
| 72 |
-
--
|
| 73 |
-
--
|
| 74 |
-
--
|
| 75 |
-
--
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
}
|
| 77 |
}
|
| 78 |
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
@@ -81,72 +98,101 @@ function renderLoginPage({ title, description, hint }: LoginPageOptions): string
|
|
| 81 |
display: flex;
|
| 82 |
align-items: center;
|
| 83 |
justify-content: center;
|
| 84 |
-
padding:
|
| 85 |
font-family: var(--font-stack);
|
| 86 |
-
background:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
color: var(--text-color);
|
| 88 |
-webkit-font-smoothing: antialiased;
|
|
|
|
| 89 |
}
|
| 90 |
.login {
|
|
|
|
|
|
|
|
|
|
| 91 |
text-align: center;
|
| 92 |
-
max-width:
|
| 93 |
width: 100%;
|
| 94 |
}
|
| 95 |
.login__title {
|
| 96 |
-
|
|
|
|
| 97 |
font-weight: 600;
|
| 98 |
-
letter-spacing: -0.
|
| 99 |
-
|
|
|
|
| 100 |
}
|
| 101 |
.login__description {
|
| 102 |
-
|
| 103 |
-
|
|
|
|
| 104 |
color: var(--muted-color);
|
| 105 |
-
margin-bottom:
|
| 106 |
}
|
| 107 |
.login__btn {
|
| 108 |
display: inline-flex;
|
| 109 |
align-items: center;
|
| 110 |
-
gap:
|
| 111 |
-
padding: 14px
|
| 112 |
font-family: inherit;
|
| 113 |
font-size: 1rem;
|
| 114 |
font-weight: 600;
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
text-decoration: none;
|
| 120 |
cursor: pointer;
|
| 121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
}
|
| 123 |
.login__btn:hover {
|
| 124 |
-
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
}
|
| 127 |
.login__btn:active {
|
| 128 |
-
transform: translateY(
|
|
|
|
| 129 |
}
|
| 130 |
.login__btn:focus-visible {
|
| 131 |
outline: 2px solid var(--primary-color);
|
| 132 |
-
outline-offset:
|
| 133 |
}
|
| 134 |
.login__btn svg {
|
| 135 |
flex-shrink: 0;
|
| 136 |
display: block;
|
|
|
|
| 137 |
}
|
| 138 |
-
.
|
| 139 |
-
margin-top:
|
| 140 |
-
font-size: 0.
|
|
|
|
|
|
|
| 141 |
color: var(--muted-color);
|
| 142 |
-
|
| 143 |
-
.login__hint-link {
|
| 144 |
-
color: var(--primary-color);
|
| 145 |
-
text-decoration: none;
|
| 146 |
-
border-bottom: 1px dashed color-mix(in srgb, var(--primary-color) 50%, transparent);
|
| 147 |
-
}
|
| 148 |
-
.login__hint-link:hover {
|
| 149 |
-
border-bottom-style: solid;
|
| 150 |
}
|
| 151 |
</style>
|
| 152 |
</head>
|
|
@@ -158,7 +204,7 @@ function renderLoginPage({ title, description, hint }: LoginPageOptions): string
|
|
| 158 |
${HF_LOGO_SVG}
|
| 159 |
<span>Sign in with Hugging Face</span>
|
| 160 |
</a>
|
| 161 |
-
|
| 162 |
</main>
|
| 163 |
</body>
|
| 164 |
</html>`;
|
|
@@ -177,7 +223,7 @@ function sendLoginPage(res: express.Response) {
|
|
| 177 |
res.status(200).send(
|
| 178 |
renderLoginPage({
|
| 179 |
title: "This article is not yet published",
|
| 180 |
-
description: "
|
| 181 |
}),
|
| 182 |
);
|
| 183 |
}
|
|
@@ -314,7 +360,6 @@ export function createApp() {
|
|
| 314 |
renderLoginPage({
|
| 315 |
title: "Editor access",
|
| 316 |
description: "Sign in with your Hugging Face account to start editing.",
|
| 317 |
-
hint: "After signing in, come back and {refresh}.",
|
| 318 |
}),
|
| 319 |
);
|
| 320 |
return;
|
|
|
|
| 21 |
const DEFAULT_DOC_NAME = "default";
|
| 22 |
|
| 23 |
/**
|
| 24 |
+
* Full inline SVG of the official Hugging Face brand logo (smiling face
|
| 25 |
+
* with both hugging hands). Drawn from
|
| 26 |
+
* https://huggingface.co/front/assets/huggingface_logo-noborder.svg
|
| 27 |
+
* so the page has zero network dependencies.
|
| 28 |
*/
|
| 29 |
+
const HF_LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95 88" width="22" height="20" aria-hidden="true" focusable="false">
|
| 30 |
<path fill="#FFD21E" d="M47.21 76.5a34.75 34.75 0 1 0 0-69.5 34.75 34.75 0 0 0 0 69.5Z"/>
|
| 31 |
<path fill="#FF9D0B" d="M81.96 41.75a34.75 34.75 0 1 0-69.5 0 34.75 34.75 0 0 0 69.5 0Zm-73.5 0a38.75 38.75 0 1 1 77.5 0 38.75 38.75 0 0 1-77.5 0Z"/>
|
| 32 |
<path fill="#3A3B45" d="M58.5 32.3c1.28.44 1.78 3.06 3.07 2.38a5 5 0 1 0-6.76-2.07c.61 1.15 2.55-.72 3.7-.32ZM34.95 32.3c-1.28.44-1.79 3.06-3.07 2.38a5 5 0 1 1 6.76-2.07c-.61 1.15-2.56-.72-3.7-.32Z"/>
|
| 33 |
<path fill="#FF323D" d="M46.96 56.29c9.83 0 13-8.76 13-13.26 0-2.34-1.57-1.6-4.09-.36-2.33 1.15-5.46 2.74-8.9 2.74-7.19 0-13-6.88-13-2.38s3.16 13.26 13 13.26Z"/>
|
| 34 |
<path fill="#3A3B45" fill-rule="evenodd" d="M39.43 54a8.7 8.7 0 0 1 5.3-4.49c.4-.12.81.57 1.24 1.28.4.68.82 1.37 1.24 1.37.45 0 .9-.68 1.33-1.35.45-.7.89-1.38 1.32-1.25a8.61 8.61 0 0 1 5 4.17c3.73-2.94 5.1-7.74 5.1-10.7 0-2.34-1.57-1.6-4.09-.36l-.14.07c-2.31 1.15-5.39 2.67-8.77 2.67s-6.45-1.52-8.77-2.67c-2.6-1.29-4.23-2.1-4.23.29 0 3.05 1.46 8.06 5.47 10.97Z" clip-rule="evenodd"/>
|
| 35 |
<path fill="#FF9D0B" d="M70.71 37a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5ZM24.21 37a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5Z"/>
|
| 36 |
+
<path fill="#FF9D0B" d="M17.52 48c-1.62 0-3.06.66-4.07 1.87a5.97 5.97 0 0 0-1.33 3.76 7.1 7.1 0 0 0-1.94-.3c-1.55 0-2.95.59-3.94 1.66a5.8 5.8 0 0 0-.8 7 5.3 5.3 0 0 0-1.79 2.82c-.24.9-.48 2.8.8 4.74a5.22 5.22 0 0 0-.37 5.02c1.02 2.32 3.57 4.14 8.52 6.1 3.07 1.22 5.89 2 5.91 2.01a44.33 44.33 0 0 0 10.93 1.6c5.86 0 10.05-1.8 12.46-5.34 3.88-5.69 3.33-10.9-1.7-15.92-2.77-2.78-4.62-6.87-5-7.77-.78-2.66-2.84-5.62-6.25-5.62a5.7 5.7 0 0 0-4.6 2.46c-1-1.26-1.98-2.25-2.86-2.82A7.4 7.4 0 0 0 17.52 48Zm0 4c.51 0 1.14.22 1.82.65 2.14 1.36 6.25 8.43 7.76 11.18.5.92 1.37 1.31 2.14 1.31 1.55 0 2.75-1.53.15-3.48-3.92-2.93-2.55-7.72-.68-8.01.08-.02.17-.02.24-.02 1.7 0 2.45 2.93 2.45 2.93s2.2 5.52 5.98 9.3c3.77 3.77 3.97 6.8 1.22 10.83-1.88 2.75-5.47 3.58-9.16 3.58-3.81 0-7.73-.9-9.92-1.46-.11-.03-13.45-3.8-11.76-7 .28-.54.75-.76 1.34-.76 2.38 0 6.7 3.54 8.57 3.54.41 0 .7-.17.83-.6.79-2.85-12.06-4.05-10.98-8.17.2-.73.71-1.02 1.44-1.02 3.14 0 10.2 5.53 11.68 5.53.11 0 .2-.03.24-.1.74-1.2.33-2.04-4.9-5.2-5.21-3.16-8.88-5.06-6.8-7.33.24-.26.58-.38 1-.38 3.17 0 10.66 6.82 10.66 6.82s2.02 2.1 3.25 2.1c.28 0 .52-.1.68-.38.86-1.46-8.06-8.22-8.56-11.01-.34-1.9.24-2.85 1.31-2.85Z"/>
|
| 37 |
+
<path fill="#FFD21E" d="M38.6 76.69c2.75-4.04 2.55-7.07-1.22-10.84-3.78-3.77-5.98-9.3-5.98-9.3s-.82-3.2-2.69-2.9c-1.87.3-3.24 5.08.68 8.01 3.91 2.93-.78 4.92-2.29 2.17-1.5-2.75-5.62-9.82-7.76-11.18-2.13-1.35-3.63-.6-3.13 2.2.5 2.79 9.43 9.55 8.56 11-.87 1.47-3.93-1.71-3.93-1.71s-9.57-8.71-11.66-6.44c-2.08 2.27 1.59 4.17 6.8 7.33 5.23 3.16 5.64 4 4.9 5.2-.75 1.2-12.28-8.53-13.36-4.4-1.08 4.11 11.77 5.3 10.98 8.15-.8 2.85-9.06-5.38-10.74-2.18-1.7 3.21 11.65 6.98 11.76 7.01 4.3 1.12 15.25 3.49 19.08-2.12Z"/>
|
| 38 |
+
<path fill="#FF9D0B" d="M77.4 48c1.62 0 3.07.66 4.07 1.87a5.97 5.97 0 0 1 1.33 3.76 7.1 7.1 0 0 1 1.95-.3c1.55 0 2.95.59 3.94 1.66a5.8 5.8 0 0 1 .8 7 5.3 5.3 0 0 1 1.78 2.82c.24.9.48 2.8-.8 4.74a5.22 5.22 0 0 1 .37 5.02c-1.02 2.32-3.57 4.14-8.51 6.1-3.08 1.22-5.9 2-5.92 2.01a44.33 44.33 0 0 1-10.93 1.6c-5.86 0-10.05-1.8-12.46-5.34-3.88-5.69-3.33-10.9 1.7-15.92 2.78-2.78 4.63-6.87 5.01-7.77.78-2.66 2.83-5.62 6.24-5.62a5.7 5.7 0 0 1 4.6 2.46c1-1.26 1.98-2.25 2.87-2.82A7.4 7.4 0 0 1 77.4 48Zm0 4c-.51 0-1.13.22-1.82.65-2.13 1.36-6.25 8.43-7.76 11.18a2.43 2.43 0 0 1-2.14 1.31c-1.54 0-2.75-1.53-.14-3.48 3.91-2.93 2.54-7.72.67-8.01a1.54 1.54 0 0 0-.24-.02c-1.7 0-2.45 2.93-2.45 2.93s-2.2 5.52-5.97 9.3c-3.78 3.77-3.98 6.8-1.22 10.83 1.87 2.75 5.47 3.58 9.15 3.58 3.82 0 7.73-.9 9.93-1.46.1-.03 13.45-3.8 11.76-7-.29-.54-.75-.76-1.34-.76-2.38 0-6.71 3.54-8.57 3.54-.42 0-.71-.17-.83-.6-.8-2.85 12.05-4.05 10.97-8.17-.19-.73-.7-1.02-1.44-1.02-3.14 0-10.2 5.53-11.68 5.53-.1 0-.19-.03-.23-.1-.74-1.2-.34-2.04 4.88-5.2 5.23-3.16 8.9-5.06 6.8-7.33-.23-.26-.57-.38-.98-.38-3.18 0-10.67 6.82-10.67 6.82s-2.02 2.1-3.24 2.1a.74.74 0 0 1-.68-.38c-.87-1.46 8.05-8.22 8.55-11.01.34-1.9-.24-2.85-1.31-2.85Z"/>
|
| 39 |
+
<path fill="#FFD21E" d="M56.33 76.69c-2.75-4.04-2.56-7.07 1.22-10.84 3.77-3.77 5.97-9.3 5.97-9.3s.82-3.2 2.7-2.9c1.86.3 3.23 5.08-.68 8.01-3.92 2.93.78 4.92 2.28 2.17 1.51-2.75 5.63-9.82 7.76-11.18 2.13-1.35 3.64-.6 3.13 2.2-.5 2.79-9.42 9.55-8.55 11 .86 1.47 3.92-1.71 3.92-1.71s9.58-8.71 11.66-6.44c2.08 2.27-1.58 4.17-6.8 7.33-5.23 3.16-5.63 4-4.9 5.2.75 1.2 12.28-8.53 13.36-4.4 1.08 4.11-11.76 5.3-10.97 8.15.8 2.85 9.05-5.38 10.74-2.18 1.69 3.21-11.65 6.98-11.76 7.01-4.31 1.12-15.26 3.49-19.08-2.12Z"/>
|
| 40 |
</svg>`;
|
| 41 |
|
| 42 |
interface LoginPageOptions {
|
| 43 |
title: string;
|
| 44 |
description: string;
|
|
|
|
|
|
|
| 45 |
}
|
| 46 |
|
| 47 |
+
function renderLoginPage({ title, description }: LoginPageOptions): string {
|
| 48 |
const safeTitle = escapeHtml(title);
|
| 49 |
const safeDescription = escapeHtml(description);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
return `<!DOCTYPE html>
|
| 52 |
<html lang="en">
|
|
|
|
| 57 |
<style>
|
| 58 |
:root {
|
| 59 |
--primary-color: oklch(0.75 0.12 47);
|
| 60 |
+
--primary-color-hover: oklch(from var(--primary-color) calc(l - 0.06) c h);
|
| 61 |
+
--primary-color-active: oklch(from var(--primary-color) calc(l - 0.10) c h);
|
| 62 |
+
--on-primary: #1a0f0a;
|
| 63 |
+
--page-bg: #fafaf9;
|
| 64 |
+
--text-color: #1a1a1a;
|
| 65 |
+
--muted-color: rgba(0, 0, 0, .58);
|
| 66 |
+
--shadow-soft:
|
| 67 |
+
0 1px 1px rgba(0, 0, 0, .04),
|
| 68 |
+
0 4px 10px rgba(0, 0, 0, .04),
|
| 69 |
+
0 16px 32px rgba(0, 0, 0, .05);
|
| 70 |
+
--shadow-button:
|
| 71 |
+
inset 0 1px 0 rgba(255, 255, 255, .25),
|
| 72 |
+
inset 0 -1px 0 rgba(0, 0, 0, .12),
|
| 73 |
+
0 1px 2px rgba(0, 0, 0, .12),
|
| 74 |
+
0 6px 16px color-mix(in srgb, var(--primary-color) 30%, transparent);
|
| 75 |
+
--shadow-button-hover:
|
| 76 |
+
inset 0 1px 0 rgba(255, 255, 255, .3),
|
| 77 |
+
inset 0 -1px 0 rgba(0, 0, 0, .12),
|
| 78 |
+
0 2px 4px rgba(0, 0, 0, .14),
|
| 79 |
+
0 10px 26px color-mix(in srgb, var(--primary-color) 38%, transparent);
|
| 80 |
+
--font-stack: "Source Sans Pro", -apple-system, BlinkMacSystemFont,
|
| 81 |
+
"SF Pro Display", "SF Pro Text", "Segoe UI", system-ui, sans-serif;
|
| 82 |
}
|
| 83 |
@media (prefers-color-scheme: dark) {
|
| 84 |
:root {
|
| 85 |
+
--on-primary: #0f1115;
|
| 86 |
+
--page-bg: #0c0d10;
|
| 87 |
+
--text-color: rgba(255, 255, 255, .92);
|
| 88 |
+
--muted-color: rgba(255, 255, 255, .58);
|
| 89 |
+
--shadow-soft:
|
| 90 |
+
0 1px 1px rgba(0, 0, 0, .35),
|
| 91 |
+
0 4px 10px rgba(0, 0, 0, .35),
|
| 92 |
+
0 16px 32px rgba(0, 0, 0, .35);
|
| 93 |
}
|
| 94 |
}
|
| 95 |
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
|
|
| 98 |
display: flex;
|
| 99 |
align-items: center;
|
| 100 |
justify-content: center;
|
| 101 |
+
padding: 32px;
|
| 102 |
font-family: var(--font-stack);
|
| 103 |
+
background:
|
| 104 |
+
radial-gradient(
|
| 105 |
+
ellipse 720px 520px at 50% -10%,
|
| 106 |
+
color-mix(in srgb, var(--primary-color) 18%, transparent),
|
| 107 |
+
transparent 65%
|
| 108 |
+
),
|
| 109 |
+
radial-gradient(
|
| 110 |
+
ellipse 480px 360px at 100% 110%,
|
| 111 |
+
color-mix(in srgb, var(--primary-color) 9%, transparent),
|
| 112 |
+
transparent 70%
|
| 113 |
+
),
|
| 114 |
+
var(--page-bg);
|
| 115 |
color: var(--text-color);
|
| 116 |
-webkit-font-smoothing: antialiased;
|
| 117 |
+
-moz-osx-font-smoothing: grayscale;
|
| 118 |
}
|
| 119 |
.login {
|
| 120 |
+
display: flex;
|
| 121 |
+
flex-direction: column;
|
| 122 |
+
align-items: center;
|
| 123 |
text-align: center;
|
| 124 |
+
max-width: 480px;
|
| 125 |
width: 100%;
|
| 126 |
}
|
| 127 |
.login__title {
|
| 128 |
+
color: var(--primary-color);
|
| 129 |
+
font-size: clamp(1.75rem, 1.4rem + 1.6vw, 2.25rem);
|
| 130 |
font-weight: 600;
|
| 131 |
+
letter-spacing: -0.025em;
|
| 132 |
+
line-height: 1.1;
|
| 133 |
+
margin-bottom: 14px;
|
| 134 |
}
|
| 135 |
.login__description {
|
| 136 |
+
max-width: 380px;
|
| 137 |
+
font-size: 1.0625rem;
|
| 138 |
+
line-height: 1.5;
|
| 139 |
color: var(--muted-color);
|
| 140 |
+
margin-bottom: 40px;
|
| 141 |
}
|
| 142 |
.login__btn {
|
| 143 |
display: inline-flex;
|
| 144 |
align-items: center;
|
| 145 |
+
gap: 10px;
|
| 146 |
+
padding: 14px 28px;
|
| 147 |
font-family: inherit;
|
| 148 |
font-size: 1rem;
|
| 149 |
font-weight: 600;
|
| 150 |
+
letter-spacing: -0.005em;
|
| 151 |
+
color: var(--on-primary);
|
| 152 |
+
background: linear-gradient(
|
| 153 |
+
180deg,
|
| 154 |
+
color-mix(in srgb, var(--primary-color) 100%, white 8%),
|
| 155 |
+
var(--primary-color)
|
| 156 |
+
);
|
| 157 |
+
border: 0;
|
| 158 |
+
border-radius: 999px;
|
| 159 |
text-decoration: none;
|
| 160 |
cursor: pointer;
|
| 161 |
+
box-shadow: var(--shadow-button);
|
| 162 |
+
transition:
|
| 163 |
+
transform 180ms cubic-bezier(.2, .9, .3, 1),
|
| 164 |
+
box-shadow 180ms ease,
|
| 165 |
+
background 180ms ease;
|
| 166 |
}
|
| 167 |
.login__btn:hover {
|
| 168 |
+
transform: translateY(-1px);
|
| 169 |
+
background: linear-gradient(
|
| 170 |
+
180deg,
|
| 171 |
+
color-mix(in srgb, var(--primary-color-hover) 100%, white 6%),
|
| 172 |
+
var(--primary-color-hover)
|
| 173 |
+
);
|
| 174 |
+
box-shadow: var(--shadow-button-hover);
|
| 175 |
}
|
| 176 |
.login__btn:active {
|
| 177 |
+
transform: translateY(0);
|
| 178 |
+
background: var(--primary-color-active);
|
| 179 |
}
|
| 180 |
.login__btn:focus-visible {
|
| 181 |
outline: 2px solid var(--primary-color);
|
| 182 |
+
outline-offset: 4px;
|
| 183 |
}
|
| 184 |
.login__btn svg {
|
| 185 |
flex-shrink: 0;
|
| 186 |
display: block;
|
| 187 |
+
filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .15));
|
| 188 |
}
|
| 189 |
+
.login__brand {
|
| 190 |
+
margin-top: 56px;
|
| 191 |
+
font-size: 0.8125rem;
|
| 192 |
+
font-weight: 500;
|
| 193 |
+
letter-spacing: 0.02em;
|
| 194 |
color: var(--muted-color);
|
| 195 |
+
opacity: 0.85;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
}
|
| 197 |
</style>
|
| 198 |
</head>
|
|
|
|
| 204 |
${HF_LOGO_SVG}
|
| 205 |
<span>Sign in with Hugging Face</span>
|
| 206 |
</a>
|
| 207 |
+
<p class="login__brand">Research Article Template Editor</p>
|
| 208 |
</main>
|
| 209 |
</body>
|
| 210 |
</html>`;
|
|
|
|
| 223 |
res.status(200).send(
|
| 224 |
renderLoginPage({
|
| 225 |
title: "This article is not yet published",
|
| 226 |
+
description: "Sign in with your Hugging Face account to access the editor.",
|
| 227 |
}),
|
| 228 |
);
|
| 229 |
}
|
|
|
|
| 360 |
renderLoginPage({
|
| 361 |
title: "Editor access",
|
| 362 |
description: "Sign in with your Hugging Face account to start editing.",
|
|
|
|
| 363 |
}),
|
| 364 |
);
|
| 365 |
return;
|