Skip to content

Commit 0e07fb3

Browse files
committed
feat: restyle OAuth callback pages to match the site's light design
1 parent 95bc540 commit 0e07fb3

2 files changed

Lines changed: 55 additions & 22 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pythoughts/pythinker-code": patch
3+
---
4+
5+
Restyle the browser OAuth sign-in confirmation pages for all providers to match the website's light design.

packages/oauth/src/oauth-pages.ts

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,53 +39,77 @@ const PYTHINKER_LOGO_SVG =
3939
'</svg>';
4040

4141
const SUCCESS_BADGE_SVG =
42-
'<svg class="badge-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="28" height="28" aria-hidden="true" focusable="false">' +
43-
'<circle cx="12" cy="12" r="11" fill="#1a3d2f" stroke="#3ecf8e" stroke-width="1.5"/>' +
44-
'<path d="M7.5 12.2l3 3 6-6.5" fill="none" stroke="#3ecf8e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>' +
42+
'<svg class="badge-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="44" height="44" aria-hidden="true" focusable="false">' +
43+
'<circle cx="12" cy="12" r="11" fill="#f0fdf4" stroke="#15803d" stroke-width="1.5"/>' +
44+
'<path class="badge-draw" d="M7.5 12.2l3 3 6-6.5" fill="none" stroke="#15803d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>' +
4545
'</svg>';
4646

4747
const ERROR_BADGE_SVG =
48-
'<svg class="badge-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="28" height="28" aria-hidden="true" focusable="false">' +
49-
'<circle cx="12" cy="12" r="11" fill="#3d1a1a" stroke="#f87171" stroke-width="1.5"/>' +
50-
'<path d="M8.5 8.5l7 7M15.5 8.5l-7 7" fill="none" stroke="#f87171" stroke-width="2" stroke-linecap="round"/>' +
48+
'<svg class="badge-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="44" height="44" aria-hidden="true" focusable="false">' +
49+
'<circle cx="12" cy="12" r="11" fill="#fef2f2" stroke="#dc2626" stroke-width="1.5"/>' +
50+
'<path class="badge-draw" d="M8.5 8.5l7 7M15.5 8.5l-7 7" fill="none" stroke="#dc2626" stroke-width="2" stroke-linecap="round"/>' +
5151
'</svg>';
5252

53+
// Palette and card treatment mirror apps/site/src/style.css (light canvas,
54+
// grid background, hairline card, blue accent). Inline-only: the Inter/mono
55+
// families fall back to system fonts because this page must work offline.
56+
const GRID_BG =
57+
'url("data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'48\' height=\'48\'%3E%3Cpath d=\'M48 0H0v48\' fill=\'none\' stroke=\'%23111113\' stroke-opacity=\'0.045\' stroke-width=\'1\'/%3E%3C/svg%3E")';
58+
5359
const PAGE_STYLES =
60+
':root{color-scheme:light}' +
5461
'*,*::before,*::after{box-sizing:border-box}' +
5562
'html,body{height:100%;margin:0}' +
5663
'body{' +
57-
'font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;' +
58-
'background:#0b0f19;' +
59-
'background-image:radial-gradient(ellipse 80% 60% at 50% -10%,rgba(62,207,142,.12),transparent),' +
60-
'radial-gradient(ellipse 60% 50% at 100% 100%,rgba(238,154,135,.08),transparent);' +
61-
'color:#e8eaed;' +
64+
"font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',helvetica,arial,sans-serif;" +
65+
`background-color:#ffffff;background-image:${GRID_BG};color:#111113;` +
6266
'display:flex;align-items:center;justify-content:center;padding:24px;' +
6367
'}' +
6468
'.card{' +
65-
'width:min(100%,480px);padding:48px 40px 44px;border-radius:20px;' +
66-
'background:linear-gradient(180deg,#1a2030 0%,#161b22 100%);' +
67-
'border:1px solid #2d333b;' +
68-
'box-shadow:0 24px 48px rgba(0,0,0,.35),0 0 0 1px rgba(255,255,255,.04) inset;' +
69+
'width:min(100%,440px);padding:40px 36px 32px;border-radius:18px;' +
70+
'background:#ffffff;' +
71+
'border:1px solid #e5e7eb;' +
72+
'box-shadow:0 24px 70px -42px rgba(17,17,19,.35);' +
6973
'display:flex;flex-direction:column;align-items:center;text-align:center;' +
74+
'animation:card-in .35s ease-out both;' +
7075
'}' +
71-
'.logo{margin-bottom:8px}' +
76+
'.logo{margin-bottom:10px}' +
77+
'.logo svg{width:64px;height:80px}' +
7278
'.brand{' +
73-
'margin:0 0 28px;font-size:13px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:#6b7280;' +
79+
"margin:0 0 24px;font-family:'JetBrains Mono',ui-monospace,'SF Mono',monospace;" +
80+
'font-size:12px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;color:#8b8d94;' +
7481
'}' +
75-
'.badge{margin-bottom:16px}' +
82+
'.badge{margin-bottom:14px}' +
7683
'.badge-icon{display:block}' +
84+
'.badge-draw{stroke-dasharray:24;stroke-dashoffset:24;animation:badge-draw .4s ease-out .25s forwards}' +
7785
'h1{' +
78-
'margin:0 0 12px;font-size:26px;line-height:1.25;font-weight:650;letter-spacing:-.02em;color:#f5f7fa;' +
86+
'margin:0 0 10px;font-size:24px;line-height:1.19;font-weight:600;letter-spacing:-.025em;color:#111113;' +
87+
'}' +
88+
'p.message{' +
89+
'margin:0 0 24px;font-size:16px;line-height:1.55;color:#55565c;max-width:34ch;' +
90+
'}' +
91+
'.status{' +
92+
'width:100%;display:flex;align-items:center;justify-content:center;gap:8px;' +
93+
'padding:10px 14px;border-radius:12px;' +
94+
'background:#f7f7f8;border:1px solid #e5e7eb;' +
95+
"font-family:'JetBrains Mono',ui-monospace,'SF Mono',monospace;" +
96+
'font-size:13px;color:#55565c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;' +
7997
'}' +
80-
'p{' +
81-
'margin:0;font-size:15px;line-height:1.6;color:#9aa0a8;max-width:34ch;' +
98+
'.status .ok{color:#15803d}' +
99+
'.status .err{color:#dc2626}' +
100+
'@keyframes card-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}' +
101+
'@keyframes badge-draw{to{stroke-dashoffset:0}}' +
102+
'@media (prefers-reduced-motion:reduce){' +
103+
'.card{animation:none}' +
104+
'.badge-draw{animation:none;stroke-dashoffset:0}' +
82105
'}';
83106

84107
function renderOAuthPage(options: {
85108
readonly title: string;
86109
readonly heading: string;
87110
readonly message: string;
88111
readonly badge: string;
112+
readonly statusLine: string;
89113
}): string {
90114
return (
91115
'<!doctype html><html lang="en"><head>' +
@@ -99,7 +123,8 @@ function renderOAuthPage(options: {
99123
'<p class="brand">Pythinker Code</p>' +
100124
`<div class="badge">${options.badge}</div>` +
101125
`<h1>${options.heading}</h1>` +
102-
`<p>${options.message}</p>` +
126+
`<p class="message">${options.message}</p>` +
127+
`<div class="status" role="status">${options.statusLine}</div>` +
103128
'</main></body></html>'
104129
);
105130
}
@@ -110,6 +135,7 @@ export function renderOAuthSuccessPage(): string {
110135
heading: "You're logged in to Pythinker",
111136
message: 'You can close this tab and return to Pythinker.',
112137
badge: SUCCESS_BADGE_SVG,
138+
statusLine: 'status: <span class="ok">authenticated</span>',
113139
});
114140
}
115141

@@ -119,6 +145,7 @@ export function renderOpenAICodexOAuthSuccessPage(): string {
119145
heading: 'OpenAI Codex sign-in complete',
120146
message: 'You can close this tab and return to Pythinker Code.',
121147
badge: SUCCESS_BADGE_SVG,
148+
statusLine: 'provider: openai-codex &middot; status: <span class="ok">authenticated</span>',
122149
});
123150
}
124151

@@ -128,5 +155,6 @@ export function renderOAuthErrorPage(): string {
128155
heading: 'Sign-in failed',
129156
message: 'The authorization server reported an error. Return to Pythinker for details.',
130157
badge: ERROR_BADGE_SVG,
158+
statusLine: 'status: <span class="err">failed</span>',
131159
});
132160
}

0 commit comments

Comments
 (0)