From 2ff6b79adb285cbbc5d843bc30926cee003602db Mon Sep 17 00:00:00 2001 From: rimar1337 <132627503+rimar1337@users.noreply.github.com> Date: Sat, 9 Aug 2025 23:24:36 +0700 Subject: [PATCH] oauth (public client) --- oauthdev.mts | 48 +++ package-lock.json | 296 +++++++++++++++++- package.json | 9 +- public/client-metadata.json | 22 ++ src/components/Header.tsx | 61 +++- src/components/OAuthLogin.tsx | 124 ++++++++ src/components/{Login.tsx => PassLogin.tsx} | 0 src/components/PostError.tsx | 2 +- src/helpers/oauthClient.ts | 38 +++ src/main.tsx | 6 +- src/providers/OAuthProvider.tsx | 98 ++++++ src/routeTree.gen.ts | 21 ++ src/routes/callback/index.tsx | 11 + src/routes/f/$forumHandle/index.tsx | 6 +- .../$forumHandle/t/$userHandle/$topicRKey.tsx | 10 +- src/routes/search.tsx | 9 +- vite.config.ts | 40 ++- 17 files changed, 759 insertions(+), 42 deletions(-) create mode 100644 oauthdev.mts create mode 100644 public/client-metadata.json create mode 100644 src/components/OAuthLogin.tsx rename src/components/{Login.tsx => PassLogin.tsx} (100%) create mode 100644 src/helpers/oauthClient.ts create mode 100644 src/providers/OAuthProvider.tsx create mode 100644 src/routes/callback/index.tsx diff --git a/oauthdev.mts b/oauthdev.mts new file mode 100644 index 0000000..73382f5 --- /dev/null +++ b/oauthdev.mts @@ -0,0 +1,48 @@ +import fs from 'fs'; +import path from 'path'; +//import { generateClientMetadata } from './src/helpers/oauthClient' +export const generateClientMetadata = (appOrigin: string) => { + const callbackPath = '/callback'; + + return { + "client_id": `${appOrigin}/client-metadata.json`, + "client_name": "ForumTest", + "client_uri": appOrigin, + "logo_uri": `${appOrigin}/logo192.png`, + "tos_uri": `${appOrigin}/terms-of-service`, + "policy_uri": `${appOrigin}/privacy-policy`, + "redirect_uris": [`${appOrigin}${callbackPath}`] as [string, ...string[]], + "scope": "atproto transition:generic", + "grant_types": ["authorization_code", "refresh_token"] as ["authorization_code", "refresh_token"], + "response_types": ["code"] as ["code"], + "token_endpoint_auth_method": "none" as "none", + "application_type": "web" as "web", + "dpop_bound_access_tokens": true + }; +} + + +export function generateMetadataPlugin({prod, dev}:{prod: string, dev: string}) { + return { + name: 'vite-plugin-generate-metadata', + config(_config: any, { mode }: any) { + let appOrigin; + if (mode === 'production') { + appOrigin = prod + if (!appOrigin || !appOrigin.startsWith('https://')) { + throw new Error('VITE_APP_ORIGIN environment variable must be set to a valid HTTPS URL for production build.'); + } + } else { + appOrigin = dev; + } + + + const metadata = generateClientMetadata(appOrigin); + const outputPath = path.resolve(process.cwd(), 'public', 'client-metadata.json'); + + fs.writeFileSync(outputPath, JSON.stringify(metadata, null, 2)); + + console.log(`✅ Generated client-metadata.json for ${appOrigin}`); + }, + }; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2ae9453..f3791d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,8 +6,10 @@ "": { "name": "forumtest", "dependencies": { - "@atproto/api": "^0.16.0", + "@atproto/api": "^0.16.2", + "@atproto/oauth-client-browser": "^0.3.27", "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-popover": "^1.1.14", "@radix-ui/react-select": "^2.2.5", @@ -26,6 +28,7 @@ "devDependencies": { "@testing-library/dom": "^10.4.0", "@testing-library/react": "^16.2.0", + "@types/node": "^24.2.1", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", @@ -70,10 +73,83 @@ "dev": true, "license": "ISC" }, + "node_modules/@atproto-labs/did-resolver": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.2.0.tgz", + "integrity": "sha512-y9GOx2gUETynDKmANnBrU5DTf+u0AwKBJpGns1vDDOYMdLdRCFIeYy3UH+TI8YOkcEazjgF5Q3m+LjwriE1KqQ==", + "license": "MIT", + "dependencies": { + "@atproto-labs/fetch": "0.2.3", + "@atproto-labs/pipe": "0.1.1", + "@atproto-labs/simple-store": "0.2.0", + "@atproto-labs/simple-store-memory": "0.1.3", + "@atproto/did": "0.1.5", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto-labs/fetch": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.2.3.tgz", + "integrity": "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw==", + "license": "MIT", + "dependencies": { + "@atproto-labs/pipe": "0.1.1" + } + }, + "node_modules/@atproto-labs/handle-resolver": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.3.0.tgz", + "integrity": "sha512-TREelvXB6P2eHxx6QjINRkBzUZu/aXWrdY9iN57shQe3C8rzsHNEHHuTVvRa33Hc7vFdQbZN0TnCgKveoyiL/A==", + "license": "MIT", + "dependencies": { + "@atproto-labs/simple-store": "0.2.0", + "@atproto-labs/simple-store-memory": "0.1.3", + "@atproto/did": "0.1.5", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto-labs/identity-resolver": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.3.0.tgz", + "integrity": "sha512-ZmmRV6m17kIaX4WllYrFIa7d23lNng0fIk6pLyepRGZobQhM5d4wDezICTESAG+RoD0e5fisWs+Tamdvx3mx/Q==", + "license": "MIT", + "dependencies": { + "@atproto-labs/did-resolver": "0.2.0", + "@atproto-labs/handle-resolver": "0.3.0" + } + }, + "node_modules/@atproto-labs/pipe": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.1.tgz", + "integrity": "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg==", + "license": "MIT" + }, + "node_modules/@atproto-labs/simple-store": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.2.0.tgz", + "integrity": "sha512-0bRbAlI8Ayh03wRwncAMEAyUKtZ+AuTS1jgPrfym1WVOAOiottI/ZmgccqLl6w5MbxVcClNQF7WYGKvGwGoIhA==", + "license": "MIT" + }, + "node_modules/@atproto-labs/simple-store-memory": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.3.tgz", + "integrity": "sha512-jkitT9+AtU+0b28DoN92iURLaCt/q/q4yX8q6V+9LSwYlUTqKoj/5NFKvF7x6EBuG+gpUdlcycbH7e60gjOhRQ==", + "license": "MIT", + "dependencies": { + "@atproto-labs/simple-store": "0.2.0", + "lru-cache": "^10.2.0" + } + }, + "node_modules/@atproto-labs/simple-store-memory/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/@atproto/api": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.16.0.tgz", - "integrity": "sha512-PQHeae6mz/L1YirUslfci7bknfg3RrSZjXpYwzLICxIOvqGKIkOi0+qukC2Py238RhXRo8YZ9dCuole9HQBXDw==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.16.2.tgz", + "integrity": "sha512-sSTg31J8ws8DNaoiizp+/uJideRxRaJsq+Nyl8rnSxGw0w3oCvoeRU19iRWh2t0jZEmiRJAGkveGu23NKmPYEQ==", "license": "MIT", "dependencies": { "@atproto/common-web": "^0.4.2", @@ -98,6 +174,46 @@ "zod": "^3.23.8" } }, + "node_modules/@atproto/did": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.1.5.tgz", + "integrity": "sha512-8+1D08QdGE5TF0bB0vV8HLVrVZJeLNITpRTUVEoABNMRaUS7CoYSVb0+JNQDeJIVmqMjOL8dOjvCUDkp3gEaGQ==", + "license": "MIT", + "dependencies": { + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/jwk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.4.0.tgz", + "integrity": "sha512-tvp4iZrzqEzKCeTOKz50/o6WdsZzOuWmWjF6On5QAp04fLwLpsFu2Hixgx/lA1KBO0O4sns7YSGcAqSSX6Rdog==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.9.0", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/jwk-jose": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.9.tgz", + "integrity": "sha512-HT9GcUe6htDxI5OSYXWdeS6QZ9lpuDDvJk508ppi8a48E/1f8eumoM0QhgbFRF9IKAnnFrtnZDOAvljQzFKwwQ==", + "license": "MIT", + "dependencies": { + "@atproto/jwk": "0.4.0", + "jose": "^5.2.0" + } + }, + "node_modules/@atproto/jwk-webcrypto": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.1.9.tgz", + "integrity": "sha512-ecciePHT0JEDZNAbMKSkdqoBYsjvhwuVno0jsS600SZmuvi2fAMhGraDZ5ZOO5M0hHHBiDbN7Ar/qcnIwyoxsA==", + "license": "MIT", + "dependencies": { + "@atproto/jwk": "0.4.0", + "@atproto/jwk-jose": "0.1.9", + "zod": "^3.23.8" + } + }, "node_modules/@atproto/lexicon": { "version": "0.4.12", "resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.4.12.tgz", @@ -111,6 +227,52 @@ "zod": "^3.23.8" } }, + "node_modules/@atproto/oauth-client": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.5.1.tgz", + "integrity": "sha512-wNC9RdfH1LGyZKF+UOmY+z4TFNx1gBur3fx91MCCrNaU0aTHBzgEH9UquL2031J7VNXhBsKJnHfEB5ZYy0AEHQ==", + "license": "MIT", + "dependencies": { + "@atproto-labs/did-resolver": "0.2.0", + "@atproto-labs/fetch": "0.2.3", + "@atproto-labs/handle-resolver": "0.3.0", + "@atproto-labs/identity-resolver": "0.3.0", + "@atproto-labs/simple-store": "0.2.0", + "@atproto-labs/simple-store-memory": "0.1.3", + "@atproto/did": "0.1.5", + "@atproto/jwk": "0.4.0", + "@atproto/oauth-types": "0.4.0", + "@atproto/xrpc": "0.7.1", + "multiformats": "^9.9.0", + "zod": "^3.23.8" + } + }, + "node_modules/@atproto/oauth-client-browser": { + "version": "0.3.27", + "resolved": "https://registry.npmjs.org/@atproto/oauth-client-browser/-/oauth-client-browser-0.3.27.tgz", + "integrity": "sha512-sUZP27KjlS3qJVPMC+RgWNARQZo7n6CWCXN55+QqLnHTfh+dLCXDS9jMUreXUGMQkVETEogDZ/v0Pb0xHQwBsg==", + "license": "MIT", + "dependencies": { + "@atproto-labs/did-resolver": "0.2.0", + "@atproto-labs/handle-resolver": "0.3.0", + "@atproto-labs/simple-store": "0.2.0", + "@atproto/did": "0.1.5", + "@atproto/jwk": "0.4.0", + "@atproto/jwk-webcrypto": "0.1.9", + "@atproto/oauth-client": "0.5.1", + "@atproto/oauth-types": "0.4.0" + } + }, + "node_modules/@atproto/oauth-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.4.0.tgz", + "integrity": "sha512-FrRH9JsPw9H4JxfPDrbrI+pB102tbHTygajfHay7xwz78HPOjSbWPRgWW2hYS4w8vDYdB3PYbBj1jPoKetW7LA==", + "license": "MIT", + "dependencies": { + "@atproto/jwk": "0.4.0", + "zod": "^3.23.8" + } + }, "node_modules/@atproto/syntax": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.0.tgz", @@ -1359,6 +1521,35 @@ } } }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz", + "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.15", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", @@ -1426,6 +1617,46 @@ } } }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz", + "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.10", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.10", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popover": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz", @@ -1566,6 +1797,37 @@ } } }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-select": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", @@ -2745,6 +3007,16 @@ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, + "node_modules/@types/node": { + "version": "24.2.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz", + "integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, "node_modules/@types/react": { "version": "19.1.9", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz", @@ -3650,6 +3922,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jose": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz", + "integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/jotai": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.13.0.tgz", @@ -4802,6 +5083,13 @@ "multiformats": "^9.4.2" } }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "devOptional": true, + "license": "MIT" + }, "node_modules/unplugin": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.5.tgz", diff --git a/package.json b/package.json index 0167e4f..bf77f02 100644 --- a/package.json +++ b/package.json @@ -3,15 +3,17 @@ "private": true, "type": "module", "scripts": { - "dev": "vite --port 3000", - "start": "vite --port 3000", + "dev": "vite --port 3768", + "start": "vite --port 3768", "build": "vite build && tsc", "serve": "vite preview", "test": "vitest run" }, "dependencies": { - "@atproto/api": "^0.16.0", + "@atproto/api": "^0.16.2", + "@atproto/oauth-client-browser": "^0.3.27", "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-popover": "^1.1.14", "@radix-ui/react-select": "^2.2.5", @@ -30,6 +32,7 @@ "devDependencies": { "@testing-library/dom": "^10.4.0", "@testing-library/react": "^16.2.0", + "@types/node": "^24.2.1", "@types/react": "^19.0.8", "@types/react-dom": "^19.0.3", "@vitejs/plugin-react": "^4.3.4", diff --git a/public/client-metadata.json b/public/client-metadata.json new file mode 100644 index 0000000..4d51977 --- /dev/null +++ b/public/client-metadata.json @@ -0,0 +1,22 @@ +{ + "client_id": "https://forumtest.whey.party/client-metadata.json", + "client_name": "ForumTest", + "client_uri": "https://forumtest.whey.party", + "logo_uri": "https://forumtest.whey.party/logo192.png", + "tos_uri": "https://forumtest.whey.party/terms-of-service", + "policy_uri": "https://forumtest.whey.party/privacy-policy", + "redirect_uris": [ + "https://forumtest.whey.party/callback" + ], + "scope": "atproto transition:generic", + "grant_types": [ + "authorization_code", + "refresh_token" + ], + "response_types": [ + "code" + ], + "token_endpoint_auth_method": "none", + "application_type": "web", + "dpop_bound_access_tokens": true +} \ No newline at end of file diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 5bb68f6..dfc3b0e 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,16 +1,57 @@ import { Link } from "@tanstack/react-router"; -import Login from "./Login"; +import Login from "./OAuthLogin"; import { SearchBox } from "./Search"; +import { useCachedProfileJotai } from "@/esav/hooks"; +import { useAuth } from "@/providers/OAuthProvider"; +import { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuItem, +} from "@radix-ui/react-dropdown-menu"; +export default function Header() { + const { agent, status } = useAuth(); + const did = agent && agent.did && status === "signedIn" ? agent.did : null; + const [profile, profileloading] = useCachedProfileJotai(did); + const avatarUrl = + profile?.profile.avatar?.ref.$link && profile?.pdsUrl + ? `${profile.pdsUrl}/xrpc/com.atproto.sync.getBlob?did=${profile.did}&cid=${profile?.profile.avatar?.ref.$link}` + : undefined; -export default function Header(){ + return ( +
You are logged in!
+ {loggedInContent} +