Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cursor-oauth-buttons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@svforge/oauth': patch
'svforge': patch
---
Give enabled OAuth provider buttons a pointer cursor and retain a not-allowed cursor while sign-in is pending.
96 changes: 95 additions & 1 deletion graphify-out/graph.json
Original file line number Diff line number Diff line change
Expand Up @@ -16250,7 +16250,7 @@
},
{
"id": "packages_svforge_templates_dashboard_src_lib_client_auth",
"label": "client/auth.ts",
"label": "src/lib/client/auth.ts",
"file_type": "code",
"source_file": "packages/svforge/templates/dashboard/src/lib/client/auth.ts",
"source_location": "L1",
Expand Down Expand Up @@ -24118,6 +24118,22 @@
"source_location": "L1",
"_origin": "ast"
},
{
"id": "tests_oauth_buttons_test",
"label": "oauth-buttons.test.ts",
"file_type": "code",
"source_file": "tests/oauth-buttons.test.ts",
"source_location": "L1",
"_origin": "ast"
},
{
"id": "tests_oauth_buttons_test_socialsignin",
"label": "{ socialSignIn }",
"file_type": "code",
"source_file": "tests/oauth-buttons.test.ts",
"source_location": "L5",
"_origin": "ast"
},
{
"id": "tests_oauth_declarations_test",
"label": "oauth-declarations.test.ts",
Expand Down Expand Up @@ -24953,6 +24969,22 @@
"source_location": "L6",
"_origin": "ast"
},
{
"id": "tests_stubs_lib_client_auth",
"label": "stubs/lib/client/auth.ts",
"file_type": "code",
"source_file": "tests/stubs/lib/client/auth.ts",
"source_location": "L1",
"_origin": "ast"
},
{
"id": "tests_stubs_lib_client_auth_authclient",
"label": "authClient",
"file_type": "code",
"source_file": "tests/stubs/lib/client/auth.ts",
"source_location": "L1",
"_origin": "ast"
},
{
"id": "tests_stubs_lib_components_svforge_primitives_index_js_tests_stubs_lib_components_svforge_primitives_index",
"label": "lib/components/svforge/primitives/index.js",
Expand Down Expand Up @@ -26396,6 +26428,15 @@
"source_location": "L1",
"_origin": "ast"
},
{
"id": "changeset_cursor_oauth_buttons",
"label": "cursor-oauth-buttons.md",
"file_type": "document",
"node_kind": "page",
"source_file": ".changeset/cursor-oauth-buttons.md",
"source_location": "L1",
"_origin": "ast"
},
{
"id": "changeset_plain_base_class_derivations",
"label": "plain-base-class-derivations.md",
Expand Down Expand Up @@ -81788,6 +81829,49 @@
"source_file": "tests/npm-consumer-smoke.test.ts",
"_origin": "ast"
},
{
"source": "tests_oauth_buttons_test",
"target": "ref_vitest",
"relation": "imports_from",
"context": "import",
"confidence": "EXTRACTED",
"source_file": "tests/oauth-buttons.test.ts",
"source_location": "L2",
"weight": 1,
"_origin": "ast"
},
{
"source": "tests_oauth_buttons_test",
"target": "ref_testing_library_svelte",
"relation": "imports_from",
"context": "import",
"confidence": "EXTRACTED",
"source_file": "tests/oauth-buttons.test.ts",
"source_location": "L3",
"weight": 1,
"_origin": "ast"
},
{
"source": "tests_oauth_buttons_test",
"target": "tests_oauth_buttons_test_socialsignin",
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "tests/oauth-buttons.test.ts",
"source_location": "L5",
"weight": 1,
"_origin": "ast"
},
{
"source": "tests_oauth_buttons_test",
"target": "packages_oauth_templates_src_lib_components_svforge_ui_oauthbuttons",
"relation": "imports_from",
"context": "import",
"confidence": "EXTRACTED",
"source_file": "tests/oauth-buttons.test.ts",
"source_location": "L8",
"weight": 1,
"_origin": "ast"
},
{
"source": "tests_oauth_declarations_test",
"target": "ref_vitest",
Expand Down Expand Up @@ -84693,6 +84777,16 @@
"weight": 1,
"_origin": "ast"
},
{
"source": "tests_stubs_lib_client_auth",
"target": "tests_stubs_lib_client_auth_authclient",
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "tests/stubs/lib/client/auth.ts",
"source_location": "L1",
"weight": 1,
"_origin": "ast"
},
{
"source": "tests_stubs_lib_components_svforge_primitives_index_js_tests_stubs_lib_components_svforge_primitives_index",
"target": "tests_stubs_lib_components_svforge_primitives_index_ts_tests_stubs_lib_components_svforge_primitives_index",
Expand Down
18 changes: 15 additions & 3 deletions graphify-out/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,11 @@
"semantic_hash": ""
},
"packages/oauth/src/templates.ts": {
"ast_hash": "b5e8f3f4f97840ec7d675f79c72128a3",
"ast_hash": "48fa5e2e35b61cda9c6ab1e257b375bc",
"semantic_hash": ""
},
"packages/oauth/templates/src/lib/components/svforge/ui/OAuthButtons.svelte": {
"ast_hash": "894977405199a0cfae8a47c3dd39a484",
"ast_hash": "b1cbc7d558697ad51d9033921bdd79dc",
"semantic_hash": ""
},
"packages/oauth/tsdown.config.ts": {
Expand Down Expand Up @@ -468,7 +468,7 @@
"semantic_hash": ""
},
"packages/svforge/src/module-recipes.ts": {
"ast_hash": "2ec6703fd3a12b827fae6f1e87678689",
"ast_hash": "540ac79110d5e3c5ef73bec5c547a070",
"semantic_hash": ""
},
"packages/svforge/src/recipe-version.ts": {
Expand Down Expand Up @@ -2118,5 +2118,17 @@
".changeset/clear-avatar-initial.md": {
"ast_hash": "75e717999620fe7c44c536ab7aaf9e77",
"semantic_hash": ""
},
"tests/oauth-buttons.test.ts": {
"ast_hash": "083e1ee99d63564adbb1c1f36f91f190",
"semantic_hash": ""
},
"tests/stubs/lib/client/auth.ts": {
"ast_hash": "ac05ca4c245974ed25e4e981658ed112",
"semantic_hash": ""
},
".changeset/cursor-oauth-buttons.md": {
"ast_hash": "9bf17e5f09ab95ae546e393c1fb7dec3",
"semantic_hash": ""
}
}
2 changes: 1 addition & 1 deletion packages/oauth/src/templates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// AUTO-GENERATED - DO NOT EDIT
export const files = {
"/lib/components/svforge/ui/OAuthButtons.svelte": "<script lang=\"ts\">\n import { authClient } from '#lib/client/auth.js';\n let loading = $state<'google' | 'github' | null>(null);\n\n async function signIn(provider: 'google' | 'github') {\n loading = provider;\n try {\n await authClient.signIn.social({ provider, callbackURL: '/admin' });\n } catch (e) {\n console.error(`OAuth ${provider} failed:`, e);\n } finally {\n loading = null;\n }\n }\n</script>\n\n<div class=\"flex flex-col gap-3\">\n <button\n onclick={() => signIn('google')}\n disabled={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'google'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"/><path fill=\"currentColor\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"currentColor\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"currentColor\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n {/if}\n Google\n </button>\n\n <button\n onclick={() => signIn('github')}\n disabled={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'github'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>\n {/if}\n GitHub\n </button>\n</div>\n"
"/lib/components/svforge/ui/OAuthButtons.svelte": "<script lang=\"ts\">\n import { authClient } from '#lib/client/auth.js';\n let loading = $state<'google' | 'github' | null>(null);\n\n async function signIn(provider: 'google' | 'github') {\n if (loading !== null) return;\n loading = provider;\n try {\n await authClient.signIn.social({ provider, callbackURL: '/admin' });\n } catch (e) {\n console.error(`OAuth ${provider} failed:`, e);\n } finally {\n loading = null;\n }\n }\n</script>\n\n<div class=\"flex flex-col gap-3\">\n <button\n onclick={() => signIn('google')}\n disabled={loading !== null}\n class:cursor-pointer={loading === null}\n class:cursor-not-allowed={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'google'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"/><path fill=\"currentColor\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"currentColor\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"currentColor\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n {/if}\n Google\n </button>\n\n <button\n onclick={() => signIn('github')}\n disabled={loading !== null}\n class:cursor-pointer={loading === null}\n class:cursor-not-allowed={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'github'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>\n {/if}\n GitHub\n </button>\n</div>\n"
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
let loading = $state<'google' | 'github' | null>(null);

async function signIn(provider: 'google' | 'github') {
if (loading !== null) return;
loading = provider;
try {
await authClient.signIn.social({ provider, callbackURL: '/admin' });
Expand All @@ -18,6 +19,8 @@
<button
onclick={() => signIn('google')}
disabled={loading !== null}
class:cursor-pointer={loading === null}
class:cursor-not-allowed={loading !== null}
class="btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2"
>
{#if loading === 'google'}
Expand All @@ -31,6 +34,8 @@
<button
onclick={() => signIn('github')}
disabled={loading !== null}
class:cursor-pointer={loading === null}
class:cursor-not-allowed={loading !== null}
class="btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2"
>
{#if loading === 'github'}
Expand Down
2 changes: 1 addition & 1 deletion packages/svforge/src/module-recipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export const MODULE_RECIPE_DATA: Record<string, ModuleRecipeData> = {
"version": "2.2.0",
"dependencies": [],
"files": {
"/lib/components/svforge/ui/OAuthButtons.svelte": "<script lang=\"ts\">\n import { authClient } from '#lib/client/auth.js';\n let loading = $state<'google' | 'github' | null>(null);\n\n async function signIn(provider: 'google' | 'github') {\n loading = provider;\n try {\n await authClient.signIn.social({ provider, callbackURL: '/admin' });\n } catch (e) {\n console.error(`OAuth ${provider} failed:`, e);\n } finally {\n loading = null;\n }\n }\n</script>\n\n<div class=\"flex flex-col gap-3\">\n <button\n onclick={() => signIn('google')}\n disabled={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'google'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"/><path fill=\"currentColor\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"currentColor\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"currentColor\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n {/if}\n Google\n </button>\n\n <button\n onclick={() => signIn('github')}\n disabled={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'github'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>\n {/if}\n GitHub\n </button>\n</div>\n"
"/lib/components/svforge/ui/OAuthButtons.svelte": "<script lang=\"ts\">\n import { authClient } from '#lib/client/auth.js';\n let loading = $state<'google' | 'github' | null>(null);\n\n async function signIn(provider: 'google' | 'github') {\n if (loading !== null) return;\n loading = provider;\n try {\n await authClient.signIn.social({ provider, callbackURL: '/admin' });\n } catch (e) {\n console.error(`OAuth ${provider} failed:`, e);\n } finally {\n loading = null;\n }\n }\n</script>\n\n<div class=\"flex flex-col gap-3\">\n <button\n onclick={() => signIn('google')}\n disabled={loading !== null}\n class:cursor-pointer={loading === null}\n class:cursor-not-allowed={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'google'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\"/><path fill=\"currentColor\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"currentColor\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"currentColor\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>\n {/if}\n Google\n </button>\n\n <button\n onclick={() => signIn('github')}\n disabled={loading !== null}\n class:cursor-pointer={loading === null}\n class:cursor-not-allowed={loading !== null}\n class=\"btn preset-filled-surface-400-600 w-full flex items-center justify-center gap-2\"\n >\n {#if loading === 'github'}\n <span class=\"inline-block h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\"></span>\n {:else}\n <svg class=\"w-5 h-5\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>\n {/if}\n GitHub\n </button>\n</div>\n"
}
},
"realtime": {
Expand Down
Loading
Loading