From e67eb5e85ef72e21f32463cdb3508ad471dcf028 Mon Sep 17 00:00:00 2001 From: Test Date: Sat, 28 Feb 2026 13:08:06 +0100 Subject: [PATCH] design: add GitHub OAuth device code UI frames Two frames showing the device code waiting state (code + copy button + clickable URL + spinner) and the error state with retry button. Co-Authored-By: Claude Opus 4.6 --- design/github-oauth-fix.pen | 433 ++++++++++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 design/github-oauth-fix.pen diff --git a/design/github-oauth-fix.pen b/design/github-oauth-fix.pen new file mode 100644 index 00000000..b27f0f31 --- /dev/null +++ b/design/github-oauth-fix.pen @@ -0,0 +1,433 @@ +{ + "children": [ + { + "type": "frame", + "id": "gh_oauth_frame", + "name": "GitHub OAuth — Device Code Waiting", + "x": 0, + "y": 0, + "width": 520, + "height": "fit_content(600)", + "fill": "#ffffff", + "layout": "vertical", + "gap": 0, + "cornerRadius": [8, 8, 8, 8], + "stroke": "#e5e5e5", + "strokeWidth": 1, + "theme": { + "Mode": "Light" + }, + "children": [ + { + "type": "frame", + "id": "gh_header", + "name": "Header", + "width": "fill_container", + "height": 56, + "layout": "horizontal", + "padding": [0, 24], + "gap": 0, + "alignItems": "center", + "justifyContent": "space-between", + "children": [ + { + "type": "text", + "id": "gh_title", + "content": "Settings", + "fontFamily": "Inter", + "fontSize": 16, + "fontWeight": "600", + "fill": "#1a1a1a" + }, + { + "type": "text", + "id": "gh_close", + "content": "✕", + "fontFamily": "Inter", + "fontSize": 14, + "fill": "#888888" + } + ] + }, + { + "type": "rectangle", + "id": "gh_div1", + "width": "fill_container", + "height": 1, + "fill": "#e5e5e5" + }, + { + "type": "frame", + "id": "gh_body", + "name": "Body", + "width": "fill_container", + "layout": "vertical", + "padding": 24, + "gap": 20, + "children": [ + { + "type": "frame", + "id": "gh_section_header", + "name": "GitHub Section Header", + "layout": "vertical", + "width": "fill_container", + "gap": 4, + "children": [ + { + "type": "text", + "id": "gh_section_title", + "content": "GitHub", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600", + "fill": "#1a1a1a" + }, + { + "type": "text", + "id": "gh_section_desc", + "content": "Connect your GitHub account to clone and sync vaults.", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#888888", + "lineHeight": 1.5 + } + ] + }, + { + "type": "frame", + "id": "gh_waiting_card", + "name": "Device Code Card", + "width": "fill_container", + "layout": "vertical", + "padding": [16, 20], + "gap": 10, + "alignItems": "center", + "cornerRadius": [6, 6, 6, 6], + "stroke": "#e5e5e5", + "strokeWidth": 1, + "children": [ + { + "type": "text", + "id": "gh_prompt_text", + "content": "Enter this code on GitHub:", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#888888" + }, + { + "type": "frame", + "id": "gh_code_row", + "name": "Code + Copy", + "layout": "horizontal", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "gh_user_code", + "content": "ABCD-1234", + "fontFamily": "JetBrains Mono, monospace", + "fontSize": 24, + "fontWeight": "700", + "letterSpacing": 4, + "fill": "#1a1a1a" + }, + { + "type": "frame", + "id": "gh_copy_btn", + "name": "Copy Button", + "width": 24, + "height": 24, + "alignItems": "center", + "justifyContent": "center", + "children": [ + { + "type": "text", + "id": "gh_copy_icon", + "content": "⧉", + "fontFamily": "Inter", + "fontSize": 16, + "fill": "#888888" + } + ] + } + ] + }, + { + "type": "text", + "id": "gh_url_link", + "content": "https://github.com/login/device", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#888888", + "textDecoration": "underline" + }, + { + "type": "frame", + "id": "gh_spinner_row", + "name": "Waiting Spinner", + "layout": "horizontal", + "gap": 6, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "gh_spinner_icon", + "content": "◌", + "fontFamily": "Inter", + "fontSize": 14, + "fill": "#888888" + }, + { + "type": "text", + "id": "gh_spinner_text", + "content": "Waiting for authorization...", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#888888" + } + ] + } + ] + }, + { + "type": "frame", + "id": "gh_cancel_row", + "name": "Cancel Row", + "width": "fill_container", + "alignItems": "center", + "justifyContent": "center", + "children": [ + { + "type": "frame", + "id": "gh_cancel_btn", + "name": "Cancel Button", + "layout": "horizontal", + "padding": [6, 12], + "cornerRadius": [4, 4, 4, 4], + "stroke": "#e5e5e5", + "strokeWidth": 1, + "alignItems": "center", + "justifyContent": "center", + "children": [ + { + "type": "text", + "id": "gh_cancel_text", + "content": "Cancel", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#888888" + } + ] + } + ] + } + ] + }, + { + "type": "rectangle", + "id": "gh_div2", + "width": "fill_container", + "height": 1, + "fill": "#e5e5e5" + }, + { + "type": "frame", + "id": "gh_footer", + "name": "Footer", + "width": "fill_container", + "height": 56, + "layout": "horizontal", + "padding": [0, 24], + "alignItems": "center", + "justifyContent": "space-between", + "children": [ + { + "type": "text", + "id": "gh_shortcut", + "content": "⌘, to open settings", + "fontFamily": "Inter", + "fontSize": 11, + "fill": "#888888" + }, + { + "type": "frame", + "id": "gh_footer_buttons", + "name": "Footer Buttons", + "layout": "horizontal", + "gap": 8, + "children": [ + { + "type": "frame", + "id": "gh_cancel_footer", + "name": "Cancel", + "padding": [6, 16], + "cornerRadius": [4, 4, 4, 4], + "stroke": "#e5e5e5", + "strokeWidth": 1, + "alignItems": "center", + "justifyContent": "center", + "children": [ + { + "type": "text", + "id": "gh_cancel_f_text", + "content": "Cancel", + "fontFamily": "Inter", + "fontSize": 13, + "fill": "#1a1a1a" + } + ] + }, + { + "type": "frame", + "id": "gh_save_btn", + "name": "Save", + "padding": [6, 16], + "cornerRadius": [4, 4, 4, 4], + "fill": "#3b82f6", + "alignItems": "center", + "justifyContent": "center", + "children": [ + { + "type": "text", + "id": "gh_save_text", + "content": "Save", + "fontFamily": "Inter", + "fontSize": 13, + "fill": "#ffffff" + } + ] + } + ] + } + ] + } + ] + }, + { + "type": "frame", + "id": "gh_error_frame", + "name": "GitHub OAuth — Error with Retry", + "x": 620, + "y": 0, + "width": 520, + "height": "fit_content(300)", + "fill": "#ffffff", + "layout": "vertical", + "padding": 24, + "gap": 16, + "cornerRadius": [8, 8, 8, 8], + "stroke": "#e5e5e5", + "strokeWidth": 1, + "theme": { + "Mode": "Light" + }, + "children": [ + { + "type": "frame", + "id": "gh_err_header", + "layout": "vertical", + "width": "fill_container", + "gap": 4, + "children": [ + { + "type": "text", + "id": "gh_err_title", + "content": "GitHub", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "600", + "fill": "#1a1a1a" + }, + { + "type": "text", + "id": "gh_err_desc", + "content": "Connect your GitHub account to clone and sync vaults.", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#888888", + "lineHeight": 1.5 + } + ] + }, + { + "type": "frame", + "id": "gh_login_btn", + "name": "Login Button", + "width": "fill_container", + "height": 36, + "fill": "#1a1a1a", + "cornerRadius": [6, 6, 6, 6], + "layout": "horizontal", + "gap": 8, + "alignItems": "center", + "justifyContent": "center", + "children": [ + { + "type": "text", + "id": "gh_login_icon", + "content": "⬤", + "fontFamily": "Inter", + "fontSize": 14, + "fill": "#ffffff" + }, + { + "type": "text", + "id": "gh_login_text", + "content": "Login with GitHub", + "fontFamily": "Inter", + "fontSize": 13, + "fontWeight": "500", + "fill": "#ffffff" + } + ] + }, + { + "type": "frame", + "id": "gh_error_row", + "name": "Error + Retry", + "layout": "horizontal", + "gap": 8, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "gh_error_msg", + "content": "Authorization expired. Please try again.", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#e03e3e" + }, + { + "type": "frame", + "id": "gh_retry_btn", + "name": "Retry Button", + "layout": "horizontal", + "gap": 4, + "alignItems": "center", + "children": [ + { + "type": "text", + "id": "gh_retry_icon", + "content": "↻", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#e03e3e" + }, + { + "type": "text", + "id": "gh_retry_text", + "content": "Retry", + "fontFamily": "Inter", + "fontSize": 12, + "fill": "#e03e3e" + } + ] + } + ] + } + ] + } + ], + "variables": {} +} \ No newline at end of file