diff --git a/examples/react-sdk/package-lock.json b/examples/react-sdk/package-lock.json index 45614a72..bef23280 100644 --- a/examples/react-sdk/package-lock.json +++ b/examples/react-sdk/package-lock.json @@ -8,7 +8,7 @@ "name": "react-sdk", "version": "0.0.0", "dependencies": { - "@corbado/react-sdk": "^0.1.7-alpha.8", + "@corbado/react-sdk": "^1.0.2", "jwt-decode": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -411,20 +411,20 @@ } }, "node_modules/@corbado/react-sdk": { - "version": "0.1.7-alpha.8", - "resolved": "https://registry.npmjs.org/@corbado/react-sdk/-/react-sdk-0.1.7-alpha.8.tgz", - "integrity": "sha512-i7g+0Vue1wiBL9fbBzVEZF1s7wniO7LpequSisg1aYV5r9ICbSeXKl0YdAG/IkhLR38/Bl3pKG8tlcG1xFLr/g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@corbado/react-sdk/-/react-sdk-1.0.2.tgz", + "integrity": "sha512-XjOFDbjhIt7rgWIgHfWuXeFVyNJu08mVwltztYNQgBn2Oc/TDGr+QRVKoL0KxSvtgeInLXVXV5EiZdEVUBNzGw==", "dependencies": { - "@corbado/web-core": "^0.1.7-alpha.8" + "@corbado/web-core": "^1.0.2" }, "peerDependencies": { "react": ">=18.0.0" } }, "node_modules/@corbado/web-core": { - "version": "0.1.7-alpha.8", - "resolved": "https://registry.npmjs.org/@corbado/web-core/-/web-core-0.1.7-alpha.8.tgz", - "integrity": "sha512-Aq9m2Ara248myRxxyvrFFJbmNCML6EMzvGADQdBkZ2xtRz6WgGlJSKCBiLIdp5BO0ds4TWaw8SqYeyrYxgbnSQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@corbado/web-core/-/web-core-1.0.2.tgz", + "integrity": "sha512-8ZChtqrHpJfU4J/I8DaJLfZYobXvSoAVQoXQL6XOtSuW83vlZ+pUpACR4+SSlxZvBfGQ9rTEWJS8NOgEo0Btyw==", "dependencies": { "@github/webauthn-json": "^2.1.1", "axios": "^1.6.0", @@ -1712,9 +1712,9 @@ } }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.6.tgz", + "integrity": "sha512-XZLZDFfXKM9U/Y/B4nNynfCRUqNyVZ4sBC/n9GDRCkq9vd2mIvKjKKsbIh1WPmHmNbg6ND7cTBY3Y2+u1G3/2Q==", "dependencies": { "follow-redirects": "^1.15.4", "form-data": "^4.0.0", diff --git a/examples/react-sdk/package.json b/examples/react-sdk/package.json index 2b90a584..b5f8bd1c 100644 --- a/examples/react-sdk/package.json +++ b/examples/react-sdk/package.json @@ -10,7 +10,7 @@ "preview": "vite preview" }, "dependencies": { - "@corbado/react-sdk": "^0.1.7-alpha.8", + "@corbado/react-sdk": "^1.0.2", "jwt-decode": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/examples/react/package-lock.json b/examples/react/package-lock.json index e5804930..bc018e46 100644 --- a/examples/react/package-lock.json +++ b/examples/react/package-lock.json @@ -8,12 +8,19 @@ "name": "react", "version": "0.0.0", "dependencies": { - "@corbado/react": "^0.1.1-alpha.6", + "@corbado/react": "^1.0.3", + "@fortawesome/fontawesome-svg-core": "^6.5.1", + "@fortawesome/free-brands-svg-icons": "^6.5.1", + "@fortawesome/free-regular-svg-icons": "^6.5.1", + "@fortawesome/free-solid-svg-icons": "^6.5.1", + "@fortawesome/react-fontawesome": "^0.2.0", + "prismjs": "^1.29.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.21.1" }, "devDependencies": { + "@types/prismjs": "^1.26.3", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^6.14.0", @@ -420,12 +427,12 @@ } }, "node_modules/@corbado/react": { - "version": "0.1.1-alpha.8", - "resolved": "https://registry.npmjs.org/@corbado/react/-/react-0.1.1-alpha.8.tgz", - "integrity": "sha512-NQafxdJEwtywvcOmoiC7e50Dzb6OtJ8CHDR2pHLB/p2u8t40qAep4S5mo4k0LhohSms8uHVZJe0H4Eb6HkJHsQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@corbado/react/-/react-1.0.3.tgz", + "integrity": "sha512-VGwCpaoCsdonA1sle+MxJxyl13AWWz6TsaG2/ucJjJub7BLtW7EUQm7nXEDuwRdcF+yGt3/WU6QDC6ni4O3dJg==", "dependencies": { - "@corbado/react-sdk": "^0.1.7-alpha.8", - "@corbado/shared-ui": "^0.1.1-alpha.8", + "@corbado/react-sdk": "^1.0.2", + "@corbado/shared-ui": "^1.0.3", "i18next": "23.5.1", "i18next-browser-languagedetector": "7.1.0", "react-i18next": "13.2.2" @@ -436,29 +443,29 @@ } }, "node_modules/@corbado/react-sdk": { - "version": "0.1.7-alpha.8", - "resolved": "https://registry.npmjs.org/@corbado/react-sdk/-/react-sdk-0.1.7-alpha.8.tgz", - "integrity": "sha512-i7g+0Vue1wiBL9fbBzVEZF1s7wniO7LpequSisg1aYV5r9ICbSeXKl0YdAG/IkhLR38/Bl3pKG8tlcG1xFLr/g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@corbado/react-sdk/-/react-sdk-1.0.2.tgz", + "integrity": "sha512-XjOFDbjhIt7rgWIgHfWuXeFVyNJu08mVwltztYNQgBn2Oc/TDGr+QRVKoL0KxSvtgeInLXVXV5EiZdEVUBNzGw==", "dependencies": { - "@corbado/web-core": "^0.1.7-alpha.8" + "@corbado/web-core": "^1.0.2" }, "peerDependencies": { "react": ">=18.0.0" } }, "node_modules/@corbado/shared-ui": { - "version": "0.1.1-alpha.8", - "resolved": "https://registry.npmjs.org/@corbado/shared-ui/-/shared-ui-0.1.1-alpha.8.tgz", - "integrity": "sha512-vKpyHgec9cAhxdkff7l3dvNoEmnQ/BNypOQxXIH3E0yN1tXeQq05M/16uWnheNJ3ZV4ZA95b8XJHJUgrxQmNsg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@corbado/shared-ui/-/shared-ui-1.0.3.tgz", + "integrity": "sha512-Tj4C4g39AzaJUyPhRVYNKcLkstYlnzEhq4/T+rV9SJbyGKeCaC/WqneDSbn9JXzy64J1IRCKOH9ZKtAsKmJ0jQ==", "dependencies": { - "@corbado/web-core": "^0.1.7-alpha.8", + "@corbado/web-core": "^1.0.2", "ua-parser-js": "^1.0.37" } }, "node_modules/@corbado/web-core": { - "version": "0.1.7-alpha.8", - "resolved": "https://registry.npmjs.org/@corbado/web-core/-/web-core-0.1.7-alpha.8.tgz", - "integrity": "sha512-Aq9m2Ara248myRxxyvrFFJbmNCML6EMzvGADQdBkZ2xtRz6WgGlJSKCBiLIdp5BO0ds4TWaw8SqYeyrYxgbnSQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@corbado/web-core/-/web-core-1.0.2.tgz", + "integrity": "sha512-8ZChtqrHpJfU4J/I8DaJLfZYobXvSoAVQoXQL6XOtSuW83vlZ+pUpACR4+SSlxZvBfGQ9rTEWJS8NOgEo0Btyw==", "dependencies": { "@github/webauthn-json": "^2.1.1", "axios": "^1.6.0", @@ -928,6 +935,75 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", + "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz", + "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.1.tgz", + "integrity": "sha512-093l7DAkx0aEtBq66Sf19MgoZewv1zeY9/4C7vSKPO4qMwEsW/2VYTUTpBtLwfb9T2R73tXaRDPmE4UqLCYHfg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.5.1.tgz", + "integrity": "sha512-m6ShXn+wvqEU69wSP84coxLbNl7sGVZb+Ca+XZq6k30SzuP3X4TfPqtycgUh9ASwlNh5OfQCd8pDIWxl+O+LlQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz", + "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@github/webauthn-json": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@github/webauthn-json/-/webauthn-json-2.1.1.tgz", @@ -1352,6 +1428,12 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/prismjs": { + "version": "1.26.3", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz", + "integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==", + "dev": true + }, "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", @@ -1746,9 +1828,9 @@ } }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.6.tgz", + "integrity": "sha512-XZLZDFfXKM9U/Y/B4nNynfCRUqNyVZ4sBC/n9GDRCkq9vd2mIvKjKKsbIh1WPmHmNbg6ND7cTBY3Y2+u1G3/2Q==", "dependencies": { "follow-redirects": "^1.15.4", "form-data": "^4.0.0", @@ -3216,7 +3298,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3556,6 +3637,24 @@ "node": ">= 0.8.0" } }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -3634,6 +3733,11 @@ } } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/react-refresh": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", diff --git a/examples/react/package.json b/examples/react/package.json index 02c91441..48b49f11 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -10,12 +10,19 @@ "preview": "vite preview" }, "dependencies": { - "@corbado/react": "^0.1.1-alpha.6", + "@corbado/react": "^1.0.3", + "@fortawesome/fontawesome-svg-core": "^6.5.1", + "@fortawesome/free-brands-svg-icons": "^6.5.1", + "@fortawesome/free-regular-svg-icons": "^6.5.1", + "@fortawesome/free-solid-svg-icons": "^6.5.1", + "@fortawesome/react-fontawesome": "^0.2.0", + "prismjs": "^1.29.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.21.1" }, "devDependencies": { + "@types/prismjs": "^1.26.3", "@types/react": "^18.2.43", "@types/react-dom": "^18.2.17", "@typescript-eslint/eslint-plugin": "^6.14.0", diff --git a/examples/react/src/App.tsx b/examples/react/src/App.tsx index 8545a2e8..da6abb5a 100644 --- a/examples/react/src/App.tsx +++ b/examples/react/src/App.tsx @@ -1,16 +1,17 @@ import { CorbadoProvider } from '@corbado/react'; import RouteProvider from './routes'; -import englishTranslations from './translations/en'; +import { useContext } from 'react'; +import { CustomizationsContext } from './contexts/CustomizationsContext'; function App() { + const { customTheme, darkMode, customTranslation } = useContext(CustomizationsContext); + return ( diff --git a/examples/react/src/assets/corbado-custom-theme.css b/examples/react/src/assets/corbado-custom-theme.css new file mode 100644 index 00000000..e8cf1ad7 --- /dev/null +++ b/examples/react/src/assets/corbado-custom-theme.css @@ -0,0 +1,64 @@ +.corbado-custom-theme { + .cb-container { + background-color: var(--color-white); + color: var(--color-black); + border-color: var(--color-dark-brown); + } + + .cb-header, + .cb-subheader, + .cb-body { + font-family: var(--font-roboto); + color: var(--color-black); + } + + .cb-link-primary { + color: var(--color-light-brown); + } + + .cb-link-secondary { + color: var(--color-dark-brown); + } + + .cb-error { + color: var(--color-light-brown); + } + + .cb-form-input label { + color: var(--color-light-brown); + } + + .cb-button-primary { + background-color: var(--color-light-brown); + color: var(--color-white); + } + + .cb-button-primary:hover { + background-color: var(--color-dark-brown); + color: var(--color-white); + } + + .cb-button-secondary { + border-color: var(--color-light-brown); + color: var(--color-light-brown); + background-color: var(--color-white); + } + + .cb-button-secondary:hover { + background-color: var(--color-dark-brown); + } + + .cb-finger-print-icon { + background-color: var(--color-light-brown); + border-radius: 3.5rem; + } + + .cb-passkey-list-card { + background-color: var(--color-dark-brown); + color: var(--color-white); + } + + .cb-dialog { + color: var(--color-black); + } +} diff --git a/examples/react/src/assets/prism.css b/examples/react/src/assets/prism.css new file mode 100644 index 00000000..e7cabda7 --- /dev/null +++ b/examples/react/src/assets/prism.css @@ -0,0 +1,187 @@ +/* PrismJS 1.29.0 +https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+jsx+tsx+typescript&plugins=line-numbers+toolbar+copy-to-clipboard */ +code[class*='language-'], +pre[class*='language-'] { + color: #ccc; + background: 0 0; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} +:not(pre) > code[class*='language-'], +pre[class*='language-'] { + background: #2d2d2d; +} +:not(pre) > code[class*='language-'] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} +.token.block-comment, +.token.cdata, +.token.comment, +.token.doctype, +.token.prolog { + color: #999; +} +.token.punctuation { + color: #ccc; +} +.token.attr-name, +.token.deleted, +.token.namespace, +.token.tag { + color: #e2777a; +} +.token.function-name { + color: #6196cc; +} +.token.boolean, +.token.function, +.token.number { + color: #f08d49; +} +.token.class-name, +.token.constant, +.token.property, +.token.symbol { + color: #f8c555; +} +.token.atrule, +.token.builtin, +.token.important, +.token.keyword, +.token.selector { + color: #cc99cd; +} +.token.attr-value, +.token.char, +.token.regex, +.token.string, +.token.variable { + color: #7ec699; +} +.token.entity, +.token.operator, +.token.url { + color: #67cdcc; +} +.token.bold, +.token.important { + font-weight: 700; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.token.inserted { + color: green; +} +pre[class*='language-'].line-numbers { + position: relative; + padding-left: 3.8em; + counter-reset: linenumber; +} +pre[class*='language-'].line-numbers > code { + position: relative; + white-space: inherit; +} +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 3em; + letter-spacing: -1px; + border-right: 1px solid #999; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.line-numbers-rows > span { + display: block; + counter-increment: linenumber; +} +.line-numbers-rows > span:before { + content: counter(linenumber); + color: #999; + display: block; + padding-right: 0.8em; + text-align: right; +} +div.code-toolbar { + position: relative; +} +div.code-toolbar > .toolbar { + position: absolute; + z-index: 10; + top: 0.3em; + right: 0.2em; + transition: opacity 0.3s ease-in-out; + opacity: 0; +} +div.code-toolbar:hover > .toolbar { + opacity: 1; +} +div.code-toolbar:focus-within > .toolbar { + opacity: 1; +} +div.code-toolbar > .toolbar > .toolbar-item { + display: inline-block; +} +div.code-toolbar > .toolbar > .toolbar-item > a { + cursor: pointer; +} +div.code-toolbar > .toolbar > .toolbar-item > button { + background: 0 0; + border: 0; + color: inherit; + font: inherit; + line-height: normal; + overflow: visible; + padding: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} +div.code-toolbar > .toolbar > .toolbar-item > a, +div.code-toolbar > .toolbar > .toolbar-item > button, +div.code-toolbar > .toolbar > .toolbar-item > span { + color: #bbb; + font-size: 0.8em; + padding: 0 0.5em; + background: #f5f2f0; + background: rgba(224, 224, 224, 0.2); + box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2); + border-radius: 0.5em; +} +div.code-toolbar > .toolbar > .toolbar-item > a:focus, +div.code-toolbar > .toolbar > .toolbar-item > a:hover, +div.code-toolbar > .toolbar > .toolbar-item > button:focus, +div.code-toolbar > .toolbar > .toolbar-item > button:hover, +div.code-toolbar > .toolbar > .toolbar-item > span:focus, +div.code-toolbar > .toolbar > .toolbar-item > span:hover { + color: inherit; + text-decoration: none; +} diff --git a/examples/react/src/assets/react.svg b/examples/react/src/assets/react.svg deleted file mode 100644 index 6c87de9b..00000000 --- a/examples/react/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/react/src/components/Demo/CorbadoComponent.tsx b/examples/react/src/components/Demo/CorbadoComponent.tsx new file mode 100644 index 00000000..b73211b9 --- /dev/null +++ b/examples/react/src/components/Demo/CorbadoComponent.tsx @@ -0,0 +1,19 @@ +import { CorbadoAuth, PasskeyList, useCorbado } from '@corbado/react'; + +export const CorbadoComponent = () => { + const { isAuthenticated, logout } = useCorbado(); + + return isAuthenticated ? ( +
+ + +
+ ) : ( + void 0} /> + ); +}; diff --git a/examples/react/src/components/Demo/DarkModeOptions.tsx b/examples/react/src/components/Demo/DarkModeOptions.tsx new file mode 100644 index 00000000..9b04e17f --- /dev/null +++ b/examples/react/src/components/Demo/DarkModeOptions.tsx @@ -0,0 +1,42 @@ +import { useContext } from 'react'; +import RadioButton from '../RadioButton'; +import { CustomizationsContext } from '../../contexts/CustomizationsContext'; + +export const DarkModeOptions = () => { + const { darkMode, setDarkMode } = useContext(CustomizationsContext); + + const handleDarkModeChange = (value: string) => { + setDarkMode(value as 'on' | 'off' | 'auto'); + }; + + return ( +
+ +
+ + setDarkMode('on')} + /> + setDarkMode('off')} + /> +
+
+ ); +}; diff --git a/examples/react/src/components/Demo/ThemeOptions.tsx b/examples/react/src/components/Demo/ThemeOptions.tsx new file mode 100644 index 00000000..1e54c270 --- /dev/null +++ b/examples/react/src/components/Demo/ThemeOptions.tsx @@ -0,0 +1,48 @@ +import { useContext } from 'react'; +import RadioButton from '../RadioButton'; +import { CustomizationsContext } from '../../contexts/CustomizationsContext'; +import { CorbadoThemes } from '@corbado/react'; + +export const ThemeOptions = () => { + const { customTheme, setCustomTheme } = useContext(CustomizationsContext); + return ( +
+ +
+ + + +
+

+ Documentation for customizing themes are{' '} + + here + +

+
+ ); +}; diff --git a/examples/react/src/components/Demo/TranslationOptions.tsx b/examples/react/src/components/Demo/TranslationOptions.tsx new file mode 100644 index 00000000..7b43b041 --- /dev/null +++ b/examples/react/src/components/Demo/TranslationOptions.tsx @@ -0,0 +1,52 @@ +import { useContext, useState } from 'react'; +import RadioButton from '../RadioButton'; +import { CustomizationsContext } from '../../contexts/CustomizationsContext'; +import englishCustomizedTranslations from '../../translations/enCustomized'; +import englishDefaultTranslations from '../../translations/enDefault'; + +export const TranslationsOptions = () => { + const { customTranslation, setCustomTranslation } = useContext(CustomizationsContext); + const [hasCustomTranslation, setHasCustomTranslation] = useState(customTranslation ? '1' : ''); + + const handleCustomTranslationChange = (value: string) => { + setHasCustomTranslation(value); + setCustomTranslation({ + en: value ? englishCustomizedTranslations : englishDefaultTranslations, + }); + }; + + return ( +
+ +
+ + +
+

+ Documentation for customizing translations are{' '} + + here + +

+
+ ); +}; diff --git a/examples/react/src/components/Demo/index.tsx b/examples/react/src/components/Demo/index.tsx new file mode 100644 index 00000000..c3d4b757 --- /dev/null +++ b/examples/react/src/components/Demo/index.tsx @@ -0,0 +1,15 @@ +import { DarkModeOptions } from './DarkModeOptions'; +import { ThemeOptions } from './ThemeOptions'; +import { TranslationsOptions } from './TranslationOptions'; +import { CorbadoComponent } from './CorbadoComponent'; + +export const Demo = () => { + return ( +
+ + + + +
+ ); +}; diff --git a/examples/react/src/components/Guide/AuthBasedSteps.tsx b/examples/react/src/components/Guide/AuthBasedSteps.tsx new file mode 100644 index 00000000..93d5571b --- /dev/null +++ b/examples/react/src/components/Guide/AuthBasedSteps.tsx @@ -0,0 +1,16 @@ +import { useCorbado } from '@corbado/react'; +import { passkeyListSnippet, authSnippet } from '../../utils/constants'; + +export const AuthBasedSteps = () => { + const { isAuthenticated } = useCorbado(); + return ( +
  • +
    + 3. Use {isAuthenticated ? `` : ``} +
    +
    +        {isAuthenticated ? passkeyListSnippet : authSnippet}
    +      
    +
  • + ); +}; diff --git a/examples/react/src/components/Guide/CommonSteps.tsx b/examples/react/src/components/Guide/CommonSteps.tsx new file mode 100644 index 00000000..73962c20 --- /dev/null +++ b/examples/react/src/components/Guide/CommonSteps.tsx @@ -0,0 +1,25 @@ +import { installCommand, providerSnippet } from '../../utils/constants'; + +export const CommonSteps = () => { + return ( + <> +
  • +
    1. Install the package
    +
    +          
    +            {installCommand}
    +          
    +        
    +
  • +
  • +
    2. Wrap your app with the CorbadoProvider
    +
    +          {providerSnippet}
    +        
    +
  • + + ); +}; diff --git a/examples/react/src/components/Guide/GuideHeader.tsx b/examples/react/src/components/Guide/GuideHeader.tsx new file mode 100644 index 00000000..92489f2d --- /dev/null +++ b/examples/react/src/components/Guide/GuideHeader.tsx @@ -0,0 +1,12 @@ +import { useCorbado } from '@corbado/react'; +import { passkeyGuideHeader, authGuideHeader, passkeyComponentBody, authComponentBody } from '../../utils/constants'; + +export const GuideHeader = () => { + const { isAuthenticated } = useCorbado(); + return ( + <> +

    {isAuthenticated ? passkeyGuideHeader : authGuideHeader}

    +

    {isAuthenticated ? passkeyComponentBody : authComponentBody}

    + + ); +}; diff --git a/examples/react/src/components/Guide/index.tsx b/examples/react/src/components/Guide/index.tsx new file mode 100644 index 00000000..58933d48 --- /dev/null +++ b/examples/react/src/components/Guide/index.tsx @@ -0,0 +1,19 @@ +import 'prismjs/components/prism-typescript'; +import 'prismjs/components/prism-jsx'; +import 'prismjs/components/prism-tsx'; +import 'prismjs/themes/prism-tomorrow.min.css'; +import { GuideHeader } from './GuideHeader'; +import { CommonSteps } from './CommonSteps'; +import { AuthBasedSteps } from './AuthBasedSteps'; + +export const Guide = () => { + return ( + <> + +
      + + +
    + + ); +}; diff --git a/examples/react/src/components/Header.tsx b/examples/react/src/components/Header.tsx index 9f32bee7..745b2189 100644 --- a/examples/react/src/components/Header.tsx +++ b/examples/react/src/components/Header.tsx @@ -1,42 +1,64 @@ -import { useCorbado } from '@corbado/react'; -import { useCallback, useMemo } from 'react'; -import { useNavigate } from 'react-router-dom'; +import { useCorbadoSession } from '@corbado/react'; +import { faGithub } from '@fortawesome/free-brands-svg-icons/faGithub'; +import { faBook } from '@fortawesome/free-solid-svg-icons/faBook'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import 'prismjs/themes/prism-tomorrow.min.css'; +import { useState } from 'react'; export const Header = () => { - const { isAuthenticated, logout, loading } = useCorbado(); - const navigate = useNavigate(); + const { user, isAuthenticated } = useCorbadoSession(); + const [bounceGihub, setBounceGithub] = useState(false); + const [bounceDocumentation, setBounceDocumentation] = useState(false); - const handleLogout = useCallback(async () => { - logout(); - navigate('/auth'); - }, [logout, navigate]); + const onMouseIn = (setBounce: (value: boolean) => void) => { + setBounce(true); + }; - const logoutButton = useMemo(() => { - return ( - - ); - }, [handleLogout]); - - const loginButton = useMemo(() => { - return ( - - ); - }, [navigate]); + const onMouseOut = (setBounce: (value: boolean) => void) => { + setBounce(false); + }; return ( -
    -

    Corbado React Test

    - {loading ? null : isAuthenticated ? logoutButton : loginButton} +
    +

    + {' '} + {isAuthenticated ? ( + `Hi ${user?.name ?? user?.orig} 👋` + ) : ( + <> + Welcome to @corbado/react 👋 + + )} +

    +

    + onMouseIn(setBounceGithub)} + onPointerOut={() => onMouseOut(setBounceGithub)} + > + {' '} + Github + + onMouseIn(setBounceDocumentation)} + onPointerOut={() => onMouseOut(setBounceDocumentation)} + > + {' '} + {' '} + Documentation + +

    ); }; diff --git a/examples/react/src/components/RadioButton.tsx b/examples/react/src/components/RadioButton.tsx new file mode 100644 index 00000000..92a7fc2a --- /dev/null +++ b/examples/react/src/components/RadioButton.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +interface Props { + onClick: (value: string) => void; + text: string; + value: string | number; + currentValue: string | number; +} + +const RadioButton: React.FC = ({ text, value, currentValue, onClick }) => { + return ( + + ); +}; + +export default RadioButton; diff --git a/examples/react/src/components/UserDetails.tsx b/examples/react/src/components/UserDetails.tsx deleted file mode 100644 index cfa45d02..00000000 --- a/examples/react/src/components/UserDetails.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useCorbadoSession, PasskeyList } from '@corbado/react'; -import { WelcomeMessage } from './WelcomeMessage'; - -export const UserDetails = () => { - const { isAuthenticated } = useCorbadoSession(); - return isAuthenticated ? ( -
    - - -
    - ) : null; -}; diff --git a/examples/react/src/components/WelcomeMessage.tsx b/examples/react/src/components/WelcomeMessage.tsx index 7ecd952b..f003d892 100644 --- a/examples/react/src/components/WelcomeMessage.tsx +++ b/examples/react/src/components/WelcomeMessage.tsx @@ -1,11 +1,11 @@ -import { useCorbadoSession } from '@corbado/react'; - export const WelcomeMessage = () => { - const { user, isAuthenticated } = useCorbadoSession(); - return isAuthenticated ? ( -
    -

    Hi {user?.orig},

    -

    Welcome to Corbado React's test application

    -
    - ) : null; + return ( + <> +

    + The @corbado/react package provides a comprehensive solution for + integrating passkey-based authentication in React applications. It simplifies the process of managing + authentication states and user sessions with easy-to-use hooks and UI components. +

    + + ); }; diff --git a/examples/react/src/contexts/CustomizationsContext.tsx b/examples/react/src/contexts/CustomizationsContext.tsx new file mode 100644 index 00000000..e07a6bd3 --- /dev/null +++ b/examples/react/src/contexts/CustomizationsContext.tsx @@ -0,0 +1,40 @@ +import { createContext, useState } from 'react'; + +interface Customizations { + customTheme: string; + customTranslation: Record | null | undefined; + darkMode: 'on' | 'off' | 'auto'; + setCustomTheme: (theme: string) => void; + setCustomTranslation: (translation: Record | null | undefined) => void; + setDarkMode: (mode: 'on' | 'off' | 'auto') => void; +} + +export const CustomizationsContext = createContext({ + customTheme: '', + customTranslation: null, + darkMode: 'auto', + setCustomTheme: () => void 0, + setCustomTranslation: () => void 0, + setDarkMode: () => void 0, +}); + +export const CustomizationsProvider = ({ children }: { children: React.ReactNode }) => { + const [customTheme, setCustomTheme] = useState(''); + const [customTranslation, setCustomTranslation] = useState | null | undefined>(null); + const [darkMode, setDarkMode] = useState<'on' | 'off' | 'auto'>('auto'); + + return ( + + {children} + + ); +}; diff --git a/examples/react/src/index.css b/examples/react/src/index.css index 1f14e863..816c4c7c 100644 --- a/examples/react/src/index.css +++ b/examples/react/src/index.css @@ -1,10 +1,9 @@ -@import url('https://fonts.googleapis.com/css2?family=Lobster&display=swap'); @tailwind base; @tailwind components; @tailwind utilities; :root { - --font-eloquent: 'Lobster'; + --font-roboto: 'Roboto'; --color-light-brown: #d2b48c; --color-dark-brown: #654321; @@ -12,57 +11,22 @@ --color-black: #000000; } -.eloquent-corbado-test { - .cb-container { - background-color: var(--color-white); - color: var(--color-black); - border-color: var(--color-dark-brown); - } - - .cb-header, - .cb-subheader, - .cb-body { - font-family: var(--font-eloquent); - color: var(--color-black); - } - - .cb-link-primary { - color: var(--color-light-brown); - } - - .cb-link-secondary { - color: var(--color-dark-brown); - } - - .cb-error { - color: var(--color-light-brown); - } - - .cb-form-input label { - color: var(--color-light-brown); - } - - .cb-button-primary { - background-color: var(--color-dark-brown); - color: var(--color-white); - } +.heading { + @apply text-4xl font-bold text-gray-800 mb-3; +} - .cb-button-primary:hover { - background-color: var(--color-black); - } +.paragraph { + @apply text-lg text-gray-600; +} - .cb-button-secondary { - border-color: var(--color-light-brown); - color: var(--color-light-brown); - background-color: var(--color-white); - } +.subheading { + @apply text-2xl font-semibold text-gray-700; +} - .cb-button-secondary:hover { - background-color: var(--color-dark-brown); - } +.dot { + transition: all 0.3s ease-in-out; +} - .cb-finger-print-icon { - background-color: var(--color-light-brown); - border-radius: 3.5rem; - } +input:checked ~ .dot { + transform: translateX(100%); } diff --git a/examples/react/src/main.tsx b/examples/react/src/main.tsx index 9bb419d3..a141770b 100644 --- a/examples/react/src/main.tsx +++ b/examples/react/src/main.tsx @@ -2,9 +2,12 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App.tsx'; import './index.css'; +import { CustomizationsProvider } from './contexts/CustomizationsContext.tsx'; ReactDOM.createRoot(document.getElementById('root')!).render( - + + + , ); diff --git a/examples/react/src/pages/AuthPage.tsx b/examples/react/src/pages/AuthPage.tsx deleted file mode 100644 index 80b5d4d7..00000000 --- a/examples/react/src/pages/AuthPage.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { CorbadoAuth } from '@corbado/react'; -import { useNavigate } from 'react-router-dom'; - -const AuthPage = () => { - const navigate = useNavigate(); - - const onLoggedIn = () => { - navigate('/'); - }; - - return ( -
    - -
    - ); -}; - -export default AuthPage; diff --git a/examples/react/src/pages/HomePage.tsx b/examples/react/src/pages/HomePage.tsx index 8dc9ee2b..cd34836e 100644 --- a/examples/react/src/pages/HomePage.tsx +++ b/examples/react/src/pages/HomePage.tsx @@ -1,12 +1,33 @@ +import { useCorbado } from '@corbado/react'; +import Prism from 'prismjs'; +import '../assets/corbado-custom-theme.css'; + +import { useEffect } from 'react'; +import { WelcomeMessage } from '../components/WelcomeMessage'; +import { Guide } from '../components/Guide'; import { Header } from '../components/Header'; -import { UserDetails } from '../components/UserDetails'; +import { Demo } from '../components/Demo'; const HomePage = () => { + const { loading } = useCorbado(); + + useEffect(() => { + Prism.highlightAll(); + }, [loading]); + return ( -
    + <>
    - -
    +
    +
    + + +
    +
    + +
    +
    + ); }; diff --git a/examples/react/src/routes.tsx b/examples/react/src/routes.tsx index a113f933..7267196b 100644 --- a/examples/react/src/routes.tsx +++ b/examples/react/src/routes.tsx @@ -1,13 +1,8 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import HomePage from './pages/HomePage'; -import AuthPage from './pages/AuthPage'; const RouteProvider = () => { const routes = [ - { - path: '/auth', - element: , - }, { path: '/', element: , diff --git a/examples/react/src/translations/en.ts b/examples/react/src/translations/enCustomized.ts similarity index 80% rename from examples/react/src/translations/en.ts rename to examples/react/src/translations/enCustomized.ts index dbefbfb9..0ae2901a 100644 --- a/examples/react/src/translations/en.ts +++ b/examples/react/src/translations/enCustomized.ts @@ -20,6 +20,11 @@ const en = { }, }, }, + passkeysList: { + button_createPasskey: 'You can create passkeys here.', + field_credentialId: 'ID: ', + field_status: 'Status of Passkey: ', + }, }; export default en; diff --git a/examples/react/src/translations/enDefault.ts b/examples/react/src/translations/enDefault.ts new file mode 100644 index 00000000..7d238756 --- /dev/null +++ b/examples/react/src/translations/enDefault.ts @@ -0,0 +1,46 @@ +const en = { + authentication: { + signup: { + start: { + header: 'Create your account', + subheader: 'You already have an account? ', + button_login: 'Log in', + button_submit: 'Continue', + textField_name: 'Name', + textField_email: 'Email address', + }, + }, + login: { + start: { + header: 'Welcome back!', + subheader: "Don't have an account yet? ", + button_signup: 'Create account', + button_submit: 'Continue', + textField_email: 'Email address', + }, + }, + }, + passkeysList: { + warning_notLoggedIn: 'Please log in to see your passkeys.', + message_noPasskeys: "You don't have any passkeys yet.", + button_createPasskey: 'Create a Passkey', + badge_synced: 'Synced', + field_credentialId: 'Credential ID: ', + field_created: 'Created: {{date}} with {{browser}} on {{os}}', + field_lastUsed: 'Last used: ', + field_status: 'Status: ', + dialog_delete: { + header: 'Delete Passkey', + body: 'Are you sure you want to delete this passkey?', + button_cancel: 'Cancel', + button_confirm: 'Yes, delete', + }, + dialog_passkeyAlreadyExists: { + header: 'Passkey already exists', + body: 'A passkey for this device already exists. If you are facing issues with your passkey, please delete it and create a new one.', + button_confirm: 'Ok', + }, + }, +}; + +export default en; diff --git a/examples/react/src/utils/constants.tsx b/examples/react/src/utils/constants.tsx new file mode 100644 index 00000000..b2db0367 --- /dev/null +++ b/examples/react/src/utils/constants.tsx @@ -0,0 +1,47 @@ +export const authGuideHeader = `Setup Passkey-based Authentication in 3 Steps`; +export const passkeyGuideHeader = 'How about we check your list of Passkeys?'; +export const authComponentBody = ( + <> + Adding SignUp/Login screens is simple with @corbado/react. The{' '} + {``} component allows your users to signUp and login with their + passkeys. Additionally, it provides fallback options like email one-time passcode for users who don't have a passkey + yet. + +); +export const passkeyComponentBody = ( + <> + You can make this possible by using the {``} component. It + shows all passkeys of the currently logged in user and allows them to add and remove passkeys. + +); +export const installCommand = `npm install @corbado/react`; +export const providerSnippet = `import { CorbadoProvider } from '@corbado/react'; + +function App() { + return ( + + {/* Your routes and other components go here */} + + + ); +} + +export default App;`; +export const authSnippet = `import { CorbadoAuth } from '@corbado/react'; + +const AuthPage = () => { + const onLoggedIn = () => { + // Navigate or perform actions after successful login + }; + + return ; +}; + +export default AuthPage;`; +export const passkeyListSnippet = `import { PasskeyList } from '@corbado/react'; + +const PasskeyListPage = () => { + return ; +}; + +export default PasskeyListPage;`; diff --git a/examples/react/tailwind.config.js b/examples/react/tailwind.config.js index 90083715..1d01ce96 100644 --- a/examples/react/tailwind.config.js +++ b/examples/react/tailwind.config.js @@ -4,7 +4,7 @@ export default { theme: { extend: { fontFamily: { - eloquent: 'var(--font-eloquent)', + roboto: 'var(--font-roboto)', }, colors: { lightBrown: 'var(--color-light-brown)',