mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-06 04:19:20 +00:00
Merge branch 'ui-builder' into next
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -21,6 +21,6 @@
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,6 @@
|
||||
[](https://github.com/better-auth/better-auth/stargazers)
|
||||
</p>
|
||||
|
||||
|
||||
> [!WARNING]
|
||||
> 🚧 This project is in beta and not yet recommended for production use. For more details, check out our [roadmap](https://github.com/orgs/better-auth/projects/2) to the v1 stable release.
|
||||
|
||||
## About the Project
|
||||
|
||||
Better Auth is framework-agnostic authentication (and authorization) library for TypeScript. It provides a comprehensive set of features out of the box and includes a plugin ecosystem that simplifies adding advanced functionalities with minimal code in short amount of time. Whether you need 2FA, multi-tenant support, or other complex features. It lets you focus on building your actual application instead of reinventing the wheel.
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
--chart-5: 27 87% 67%
|
||||
}
|
||||
.dark {
|
||||
--background: 360 50% 5%;
|
||||
--background: 0 0% 2%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 240 10% 3.9%;
|
||||
--card: 240 10% 0%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
|
||||
54
docs/app/v1/_components/v1-text.tsx
Normal file
54
docs/app/v1/_components/v1-text.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
|
||||
export const ShipText = () => {
|
||||
const voxels = [
|
||||
// V
|
||||
[0, 0],
|
||||
[0, 1],
|
||||
[0, 2],
|
||||
[1, 3],
|
||||
[2, 2],
|
||||
[2, 1],
|
||||
[2, 0],
|
||||
// 1
|
||||
[4, 0],
|
||||
[4, 1],
|
||||
[4, 2],
|
||||
[4, 3],
|
||||
// .
|
||||
[6, 3],
|
||||
// 0
|
||||
[8, 0],
|
||||
[8, 1],
|
||||
[8, 2],
|
||||
[8, 3],
|
||||
[9, 0],
|
||||
[9, 3],
|
||||
[10, 0],
|
||||
[10, 1],
|
||||
[10, 2],
|
||||
[10, 3],
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center mb-0 h-[80%]">
|
||||
<div className="grid grid-cols-11 gap-2">
|
||||
{Array.from({ length: 44 }).map((_, index) => {
|
||||
const row = Math.floor(index / 11);
|
||||
const col = index % 11;
|
||||
const isActive = voxels.some(([x, y]) => x === col && y === row);
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`w-8 h-8 ${
|
||||
isActive
|
||||
? "bg-gradient-to-tr from-stone-100 via-white/90 to-zinc-900"
|
||||
: "bg-transparent"
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
147
docs/app/v1/bg-line.tsx
Normal file
147
docs/app/v1/bg-line.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
"use client";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { motion } from "framer-motion";
|
||||
import React from "react";
|
||||
|
||||
export const BackgroundLines = ({
|
||||
children,
|
||||
className,
|
||||
svgOptions,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
svgOptions?: {
|
||||
duration?: number;
|
||||
};
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"h-[20rem] md:h-screen w-full bg-white dark:bg-black",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<SVG svgOptions={svgOptions} />
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const pathVariants = {
|
||||
initial: { strokeDashoffset: 800, strokeDasharray: "50 800" },
|
||||
animate: {
|
||||
strokeDashoffset: 0,
|
||||
strokeDasharray: "20 800",
|
||||
opacity: [0, 1, 1, 0],
|
||||
},
|
||||
};
|
||||
|
||||
const SVG = ({
|
||||
svgOptions,
|
||||
}: {
|
||||
svgOptions?: {
|
||||
duration?: number;
|
||||
};
|
||||
}) => {
|
||||
const paths = [
|
||||
"M720 450C720 450 742.459 440.315 755.249 425.626C768.039 410.937 778.88 418.741 789.478 401.499C800.076 384.258 817.06 389.269 826.741 380.436C836.423 371.603 851.957 364.826 863.182 356.242C874.408 347.657 877.993 342.678 898.867 333.214C919.741 323.75 923.618 319.88 934.875 310.177C946.133 300.474 960.784 300.837 970.584 287.701C980.384 274.564 993.538 273.334 1004.85 263.087C1016.15 252.84 1026.42 250.801 1038.22 242.1C1050.02 233.399 1065.19 230.418 1074.63 215.721C1084.07 201.024 1085.49 209.128 1112.65 194.884C1139.8 180.64 1132.49 178.205 1146.43 170.636C1160.37 163.066 1168.97 158.613 1181.46 147.982C1193.95 137.35 1191.16 131.382 1217.55 125.645C1243.93 119.907 1234.19 118.899 1254.53 100.846C1274.86 82.7922 1275.12 92.8914 1290.37 76.09C1305.62 59.2886 1313.91 62.1868 1323.19 56.7536C1332.48 51.3204 1347.93 42.8082 1361.95 32.1468C1375.96 21.4855 1374.06 25.168 1397.08 10.1863C1420.09 -4.79534 1421.41 -3.16992 1431.52 -15.0078",
|
||||
"M720 450C720 450 741.044 435.759 753.062 410.636C765.079 385.514 770.541 386.148 782.73 370.489C794.918 354.83 799.378 353.188 811.338 332.597C823.298 312.005 825.578 306.419 843.707 295.493C861.837 284.568 856.194 273.248 877.376 256.48C898.558 239.713 887.536 227.843 909.648 214.958C931.759 202.073 925.133 188.092 941.063 177.621C956.994 167.151 952.171 154.663 971.197 135.041C990.222 115.418 990.785 109.375 999.488 96.1291C1008.19 82.8827 1011.4 82.2181 1032.65 61.8861C1053.9 41.5541 1045.74 48.0281 1064.01 19.5798C1082.29 -8.86844 1077.21 -3.89415 1093.7 -19.66C1110.18 -35.4258 1105.91 -46.1146 1127.68 -60.2834C1149.46 -74.4523 1144.37 -72.1024 1154.18 -97.6802C1163.99 -123.258 1165.6 -111.332 1186.21 -135.809C1206.81 -160.285 1203.29 -160.861 1220.31 -177.633C1237.33 -194.406 1236.97 -204.408 1250.42 -214.196",
|
||||
"M720 450C720 450 712.336 437.768 690.248 407.156C668.161 376.544 672.543 394.253 665.951 365.784C659.358 337.316 647.903 347.461 636.929 323.197C625.956 298.933 626.831 303.639 609.939 281.01C593.048 258.381 598.7 255.282 582.342 242.504C565.985 229.726 566.053 217.66 559.169 197.116C552.284 176.572 549.348 171.846 529.347 156.529C509.345 141.211 522.053 134.054 505.192 115.653C488.33 97.2527 482.671 82.5627 473.599 70.7833C464.527 59.0039 464.784 50.2169 447 32.0721C429.215 13.9272 436.29 0.858563 423.534 -12.6868C410.777 -26.2322 407.424 -44.0808 394.364 -56.4916C381.303 -68.9024 373.709 -72.6804 365.591 -96.1992C357.473 -119.718 358.364 -111.509 338.222 -136.495C318.08 -161.481 322.797 -149.499 315.32 -181.761C307.843 -214.023 294.563 -202.561 285.795 -223.25C277.026 -243.94 275.199 -244.055 258.602 -263.871",
|
||||
"M720 450C720 450 738.983 448.651 790.209 446.852C841.436 445.052 816.31 441.421 861.866 437.296C907.422 433.172 886.273 437.037 930.656 436.651C975.04 436.264 951.399 432.343 1001.57 425.74C1051.73 419.138 1020.72 425.208 1072.85 424.127C1124.97 423.047 1114.39 420.097 1140.02 414.426C1165.65 408.754 1173.1 412.143 1214.55 411.063C1256.01 409.983 1242.78 406.182 1285.56 401.536C1328.35 396.889 1304.66 400.796 1354.41 399.573C1404.16 398.35 1381.34 394.315 1428.34 389.376C1475.35 384.438 1445.96 386.509 1497.93 385.313C1549.9 384.117 1534.63 382.499 1567.23 381.48",
|
||||
"M720 450C720 450 696.366 458.841 682.407 472.967C668.448 487.093 673.23 487.471 647.919 492.882C622.608 498.293 636.85 499.899 609.016 512.944C581.182 525.989 596.778 528.494 571.937 533.778C547.095 539.062 551.762 548.656 536.862 556.816C521.962 564.975 515.626 563.279 497.589 575.159C479.552 587.04 484.343 590.435 461.111 598.728C437.879 607.021 442.512 605.226 423.603 618.397C404.694 631.569 402.411 629.541 390.805 641.555C379.2 653.568 369.754 658.175 353.238 663.929C336.722 669.683 330.161 674.689 312.831 684.116C295.5 693.543 288.711 698.815 278.229 704.041C267.747 709.267 258.395 712.506 240.378 726.65C222.361 740.795 230.097 738.379 203.447 745.613C176.797 752.847 193.747 752.523 166.401 767.148C139.056 781.774 151.342 783.641 130.156 791.074C108.97 798.507 116.461 802.688 96.0974 808.817C75.7334 814.946 83.8553 819.505 59.4513 830.576C35.0473 841.648 48.2548 847.874 21.8337 853.886C-4.58739 859.898 10.5966 869.102 -16.396 874.524",
|
||||
"M720 450C720 450 695.644 482.465 682.699 506.197C669.755 529.929 671.059 521.996 643.673 556.974C616.286 591.951 625.698 590.8 606.938 615.255C588.178 639.71 592.715 642.351 569.76 665.92C546.805 689.49 557.014 687.498 538.136 722.318C519.258 757.137 520.671 760.818 503.256 774.428C485.841 788.038 491.288 790.063 463.484 831.358C435.681 872.653 437.554 867.001 425.147 885.248C412.74 903.495 411.451 911.175 389.505 934.331C367.559 957.486 375.779 966.276 352.213 990.918C328.647 1015.56 341.908 1008.07 316.804 1047.24C291.699 1086.42 301.938 1060.92 276.644 1100.23C251.349 1139.54 259.792 1138.78 243.151 1153.64",
|
||||
"M719.974 450C719.974 450 765.293 459.346 789.305 476.402C813.318 493.459 825.526 487.104 865.093 495.586C904.659 504.068 908.361 510.231 943.918 523.51C979.475 536.789 963.13 535.277 1009.79 547.428C1056.45 559.579 1062.34 555.797 1089.82 568.96C1117.31 582.124 1133.96 582.816 1159.12 592.861C1184.28 602.906 1182.84 603.359 1233.48 614.514C1284.12 625.67 1254.63 632.207 1306.33 644.465C1358.04 656.723 1359.27 656.568 1378.67 670.21C1398.07 683.852 1406.16 676.466 1456.34 692.827C1506.51 709.188 1497.73 708.471 1527.54 715.212",
|
||||
"M720 450C720 450 727.941 430.821 734.406 379.251C740.87 327.681 742.857 359.402 757.864 309.798C772.871 260.194 761.947 271.093 772.992 244.308C784.036 217.524 777.105 200.533 786.808 175.699C796.511 150.864 797.141 144.333 808.694 107.307C820.247 70.2821 812.404 88.4169 819.202 37.1016C826 -14.2137 829.525 -0.990829 839.341 -30.3874C849.157 -59.784 844.404 -61.5924 855.042 -98.7516C865.68 -135.911 862.018 -144.559 876.924 -167.488C891.83 -190.418 886.075 -213.535 892.87 -237.945C899.664 -262.355 903.01 -255.031 909.701 -305.588C916.393 -356.144 917.232 -330.612 925.531 -374.777",
|
||||
"M720 450C720 450 722.468 499.363 726.104 520.449C729.739 541.535 730.644 550.025 738.836 589.07C747.028 628.115 743.766 639.319 746.146 659.812C748.526 680.306 754.006 693.598 757.006 732.469C760.007 771.34 760.322 765.244 763.893 805.195C767.465 845.146 769.92 822.227 773.398 868.469C776.875 914.71 776.207 901.365 778.233 940.19C780.259 979.015 782.53 990.477 787.977 1010.39C793.424 1030.3 791.788 1060.01 797.243 1082.24C802.698 1104.47 801.758 1130.29 808.181 1149.64C814.604 1168.99 813.135 1171.5 818.026 1225.28C822.918 1279.06 820.269 1267.92 822.905 1293.75",
|
||||
"M720 450C720 450 737.033 492.46 757.251 515.772C777.468 539.084 768.146 548.687 785.517 570.846C802.887 593.005 814.782 609.698 824.589 634.112C834.395 658.525 838.791 656.702 855.55 695.611C872.31 734.519 875.197 724.854 890.204 764.253C905.21 803.653 899.844 790.872 919.927 820.763C940.01 850.654 939.071 862.583 954.382 886.946C969.693 911.309 968.683 909.254 993.997 945.221C1019.31 981.187 1006.67 964.436 1023.49 1007.61C1040.32 1050.79 1046.15 1038.25 1059.01 1073.05C1071.88 1107.86 1081.39 1096.19 1089.45 1131.96C1097.51 1167.73 1106.52 1162.12 1125.77 1196.89",
|
||||
"M720 450C720 450 687.302 455.326 670.489 467.898C653.676 480.47 653.159 476.959 626.58 485.127C600.002 493.295 599.626 495.362 577.94 503.841C556.254 512.319 556.35 507.426 533.958 517.44C511.566 527.454 505.82 526.441 486.464 539.172C467.108 551.904 461.312 546.36 439.357 553.508C417.402 560.657 406.993 567.736 389.393 572.603C371.794 577.47 371.139 583.76 344.54 587.931C317.941 592.102 327.375 593.682 299.411 607.275C271.447 620.868 283.617 615.022 249.868 622.622C216.119 630.223 227.07 630.86 203.77 638.635C180.47 646.41 168.948 652.487 156.407 657.28C143.866 662.073 132.426 669.534 110.894 675.555C89.3615 681.575 90.3234 680.232 61.1669 689.897C32.0105 699.562 34.3696 702.021 15.9011 709.789C-2.56738 717.558 2.38861 719.841 -29.9494 729.462C-62.2873 739.083 -52.5552 738.225 -77.4307 744.286",
|
||||
"M720 450C720 450 743.97 465.061 754.884 490.648C765.798 516.235 781.032 501.34 791.376 525.115C801.72 548.889 808.417 538.333 829.306 564.807C850.195 591.281 852.336 582.531 865.086 601.843C877.835 621.155 874.512 621.773 902.383 643.857C930.255 665.94 921.885 655.976 938.025 681.74C954.164 707.505 959.384 709.719 977.273 720.525C995.162 731.33 994.233 731.096 1015.92 757.676C1037.61 784.257 1025.74 768.848 1047.82 795.343C1069.91 821.837 1065.95 815.45 1085.93 834.73C1105.91 854.009 1110.53 848.089 1124.97 869.759C1139.4 891.428 1140.57 881.585 1158.53 911.499C1176.5 941.414 1184.96 933.829 1194.53 948.792C1204.09 963.755 1221.35 973.711 1232.08 986.224C1242.8 998.738 1257.34 1015.61 1269.99 1026.53C1282.63 1037.45 1293.81 1040.91 1307.21 1064.56",
|
||||
"M720 450C720 450 718.24 412.717 716.359 397.31C714.478 381.902 713.988 362.237 710.785 344.829C707.582 327.42 708.407 322.274 701.686 292.106C694.965 261.937 699.926 270.857 694.84 240.765C689.753 210.674 693.055 217.076 689.674 184.902C686.293 152.728 686.041 149.091 682.676 133.657C679.311 118.223 682.23 106.005 681.826 80.8297C681.423 55.6545 677.891 60.196 675.66 30.0226C673.429 -0.150848 672.665 -7.94842 668.592 -26.771C664.52 -45.5935 664.724 -43.0755 661.034 -78.7766C657.343 -114.478 658.509 -103.181 653.867 -133.45C649.226 -163.719 650.748 -150.38 647.052 -182.682C643.357 -214.984 646.125 -214.921 645.216 -238.402C644.307 -261.883 640.872 -253.4 637.237 -291.706C633.602 -330.012 634.146 -309.868 630.717 -343.769C627.288 -377.669 628.008 -370.682 626.514 -394.844",
|
||||
"M720 450C720 450 730.384 481.55 739.215 507.557C748.047 533.564 751.618 537.619 766.222 562.033C780.825 586.447 774.187 582.307 787.606 618.195C801.025 654.082 793.116 653.536 809.138 678.315C825.16 703.095 815.485 717.073 829.898 735.518C844.311 753.964 845.351 773.196 852.197 786.599C859.042 800.001 862.876 805.65 872.809 845.974C882.742 886.297 885.179 874.677 894.963 903.246C904.747 931.816 911.787 924.243 921.827 961.809C931.867 999.374 927.557 998.784 940.377 1013.59C953.197 1028.4 948.555 1055.77 966.147 1070.54C983.739 1085.31 975.539 1105.69 988.65 1125.69C1001.76 1145.69 1001.82 1141.59 1007.54 1184.37C1013.27 1227.15 1018.98 1198.8 1029.67 1241.58",
|
||||
"M720 450C720 450 684.591 447.135 657.288 439.014C629.985 430.894 618.318 435.733 600.698 431.723C583.077 427.714 566.975 425.639 537.839 423.315C508.704 420.991 501.987 418.958 476.29 413.658C450.592 408.359 460.205 410.268 416.97 408.927C373.736 407.586 396.443 401.379 359.262 396.612C322.081 391.844 327.081 393.286 300.224 391.917C273.368 390.547 264.902 385.49 241.279 382.114C217.655 378.739 205.497 378.95 181.98 377.253C158.464 375.556 150.084 369.938 117.474 366.078C84.8644 362.218 81.5401 361.501 58.8734 358.545C36.2067 355.59 33.6442 351.938 -3.92281 346.728C-41.4898 341.519 -18.6466 345.082 -61.4654 341.179C-104.284 337.275 -102.32 338.048 -121.821 332.369",
|
||||
"M720 450C720 450 714.384 428.193 708.622 410.693C702.86 393.193 705.531 397.066 703.397 372.66C701.264 348.254 697.8 345.181 691.079 330.466C684.357 315.751 686.929 312.356 683.352 292.664C679.776 272.973 679.079 273.949 674.646 255.07C670.213 236.192 670.622 244.371 665.271 214.561C659.921 184.751 659.864 200.13 653.352 172.377C646.841 144.623 647.767 151.954 644.123 136.021C640.48 120.088 638.183 107.491 636.127 96.8178C634.072 86.1443 632.548 77.5871 626.743 54.0492C620.938 30.5112 622.818 28.9757 618.613 16.577C614.407 4.17831 615.555 -13.1527 608.752 -24.5691C601.95 -35.9855 603.375 -51.0511 599.526 -60.1492C595.678 -69.2472 593.676 -79.3623 587.865 -100.431C582.053 -121.5 584.628 -117.913 578.882 -139.408C573.137 -160.903 576.516 -161.693 571.966 -182.241C567.416 -202.789 567.42 -198.681 562.834 -218.28C558.248 -237.879 555.335 -240.47 552.072 -260.968C548.808 -281.466 547.605 -280.956 541.772 -296.427C535.94 -311.898 537.352 -315.211 535.128 -336.018C532.905 -356.826 531.15 -360.702 524.129 -377.124",
|
||||
"M720 450C720 450 711.433 430.82 707.745 409.428C704.056 388.035 704.937 381.711 697.503 370.916C690.069 360.121 691.274 359.999 685.371 334.109C679.469 308.22 677.496 323.883 671.24 294.303C664.984 264.724 667.608 284.849 662.065 258.116C656.522 231.383 656.357 229.024 647.442 216.172C638.527 203.319 640.134 192.925 635.555 178.727C630.976 164.529 630.575 150.179 624.994 139.987C619.413 129.794 615.849 112.779 612.251 103.074C608.654 93.3696 606.942 85.6729 603.041 63.0758C599.14 40.4787 595.242 36.9267 589.533 23.8967C583.823 10.8666 581.18 -2.12401 576.96 -14.8333C572.739 -27.5425 572.696 -37.7703 568.334 -51.3441C563.972 -64.9179 562.14 -67.2124 556.992 -93.299C551.844 -119.386 550.685 -109.743 544.056 -129.801C537.428 -149.859 534.97 -151.977 531.034 -170.076C527.099 -188.175 522.979 -185.119 519.996 -207.061C517.012 -229.004 511.045 -224.126 507.478 -247.077C503.912 -270.029 501.417 -271.033 495.534 -287C489.651 -302.968 491.488 -300.977 484.68 -326.317C477.872 -351.657 476.704 -348.494 472.792 -363.258",
|
||||
"M720 450C720 450 723.524 466.673 728.513 497.319C733.503 527.964 731.894 519.823 740.001 542.706C748.108 565.589 744.225 560.598 748.996 588.365C753.766 616.131 756.585 602.096 761.881 636.194C767.178 670.293 768.155 649.089 771.853 679.845C775.551 710.6 775.965 703.738 781.753 724.555C787.54 745.372 787.248 758.418 791.422 773.79C795.596 789.162 798.173 807.631 804.056 819.914C809.938 832.197 806.864 843.07 811.518 865.275C816.171 887.48 816.551 892.1 822.737 912.643C828.922 933.185 830.255 942.089 833.153 956.603C836.052 971.117 839.475 969.242 846.83 1003.98C854.185 1038.71 850.193 1028.86 854.119 1048.67C858.045 1068.48 857.963 1074.39 863.202 1094.94C868.44 1115.49 867.891 1108.03 874.497 1138.67C881.102 1169.31 880.502 1170.72 887.307 1186.56C894.111 1202.4 890.388 1209.75 896.507 1231.25C902.627 1252.76 902.54 1245.39 906.742 1279.23",
|
||||
"M720 450C720 450 698.654 436.893 669.785 424.902C640.916 412.91 634.741 410.601 615.568 402.586C596.396 394.571 594.829 395.346 568.66 378.206C542.492 361.067 547.454 359.714 514.087 348.978C480.721 338.242 479.79 334.731 467.646 329.846C455.502 324.96 448.63 312.156 416.039 303.755C383.448 295.354 391.682 293.73 365.021 280.975C338.36 268.219 328.715 267.114 309.809 252.575C290.903 238.036 277.185 246.984 259.529 230.958C241.873 214.931 240.502 224.403 211.912 206.241C183.323 188.078 193.288 190.89 157.03 181.714C120.772 172.538 127.621 170.109 108.253 154.714C88.8857 139.319 75.4927 138.974 56.9647 132.314C38.4366 125.654 33.8997 118.704 4.77584 106.7C-24.348 94.6959 -19.1326 90.266 -46.165 81.9082",
|
||||
"M720 450C720 450 711.596 475.85 701.025 516.114C690.455 556.378 697.124 559.466 689.441 579.079C681.758 598.693 679.099 597.524 675.382 642.732C671.665 687.94 663.4 677.024 657.844 700.179C652.288 723.333 651.086 724.914 636.904 764.536C622.723 804.158 631.218 802.853 625.414 827.056C619.611 851.259 613.734 856.28 605.94 892.262C598.146 928.244 595.403 924.314 588.884 957.785C582.364 991.255 583.079 991.176 575.561 1022.63C568.044 1054.08 566.807 1058.45 558.142 1084.32C549.476 1110.2 553.961 1129.13 542.367 1149.25C530.772 1169.37 538.268 1180.37 530.338 1207.27C522.407 1234.17 520.826 1245.53 512.156 1274.2",
|
||||
"M720 450C720 450 730.571 424.312 761.424 411.44C792.277 398.569 772.385 393.283 804.069 377.232C835.752 361.182 829.975 361.373 848.987 342.782C867.999 324.192 877.583 330.096 890.892 303.897C904.201 277.698 910.277 282.253 937.396 264.293C964.514 246.333 949.357 246.834 978.7 230.438C1008.04 214.042 990.424 217.952 1021.51 193.853C1052.6 169.753 1054.28 184.725 1065.97 158.075C1077.65 131.425 1087.76 139.068 1111.12 120.345C1134.49 101.622 1124.9 104.858 1151.67 86.3162C1178.43 67.7741 1167.09 66.2676 1197.53 47.2606C1227.96 28.2536 1225.78 23.2186 1239.27 12.9649C1252.76 2.7112 1269.32 -9.47929 1282.88 -28.5587C1296.44 -47.6381 1305.81 -41.3853 1323.82 -62.7027C1341.83 -84.0202 1340.32 -82.3794 1368.98 -98.9326",
|
||||
];
|
||||
|
||||
const colors = [
|
||||
"#46A5CA",
|
||||
"#8C2F2F",
|
||||
"#4FAE4D",
|
||||
"#D6590C",
|
||||
"#811010",
|
||||
"#247AFB",
|
||||
"#A534A0",
|
||||
"#A8A438",
|
||||
"#D6590C",
|
||||
"#46A29C",
|
||||
"#670F6D",
|
||||
"#D7C200",
|
||||
"#59BBEB",
|
||||
"#504F1C",
|
||||
"#55BC54",
|
||||
"#4D3568",
|
||||
"#9F39A5",
|
||||
"#363636",
|
||||
"#860909",
|
||||
"#6A286F",
|
||||
"#604483",
|
||||
];
|
||||
return (
|
||||
<motion.svg
|
||||
viewBox="0 0 1440 900"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 1 }}
|
||||
className="absolute inset-0 w-full h-full"
|
||||
>
|
||||
{paths.map((path, idx) => (
|
||||
<motion.path
|
||||
d={path}
|
||||
stroke={colors[idx]}
|
||||
strokeWidth="2.3"
|
||||
strokeLinecap="round"
|
||||
variants={pathVariants}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
transition={{
|
||||
duration: svgOptions?.duration || 10,
|
||||
ease: "linear",
|
||||
repeat: Infinity,
|
||||
repeatType: "loop",
|
||||
delay: Math.floor(Math.random() * 10),
|
||||
repeatDelay: Math.floor(Math.random() * 10 + 2),
|
||||
}}
|
||||
key={`path-first-${idx}`}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* duplicate for more paths */}
|
||||
{paths.map((path, idx) => (
|
||||
<motion.path
|
||||
d={path}
|
||||
stroke={colors[idx]}
|
||||
strokeWidth="2.3"
|
||||
strokeLinecap="round"
|
||||
variants={pathVariants}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
transition={{
|
||||
duration: svgOptions?.duration || 10,
|
||||
ease: "linear",
|
||||
repeat: Infinity,
|
||||
repeatType: "loop",
|
||||
delay: Math.floor(Math.random() * 10),
|
||||
repeatDelay: Math.floor(Math.random() * 10 + 2),
|
||||
}}
|
||||
key={`path-second-${idx}`}
|
||||
/>
|
||||
))}
|
||||
</motion.svg>
|
||||
);
|
||||
};
|
||||
291
docs/app/v1/page.tsx
Normal file
291
docs/app/v1/page.tsx
Normal file
@@ -0,0 +1,291 @@
|
||||
"use client";
|
||||
|
||||
import { motion } from "framer-motion";
|
||||
import { ArrowRight, GitCommit, Zap, Shield, Copy } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { ShipText } from "./_components/v1-text";
|
||||
import { ReactNode } from "react";
|
||||
import { BackgroundLines } from "./bg-line";
|
||||
import Link from "next/link";
|
||||
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||
|
||||
export default function V1Ship() {
|
||||
return (
|
||||
<div className="min-h-screen bg-transparnt overflow-hidden">
|
||||
<div className="h-[50vh] bg-transparent/10 relative">
|
||||
<BackgroundLines>
|
||||
<div className="absolute bottom-1/3 left-1/2 transform -translate-x-1/2 text-center">
|
||||
<h1 className="text-5xl mb-4">V1.0 - nov.22.2024</h1>
|
||||
<p className="text-lg text-gray-400 max-w-xl mx-auto">
|
||||
We are excited to announce the Better Auth V1.0 release.
|
||||
</p>
|
||||
</div>
|
||||
</BackgroundLines>
|
||||
</div>
|
||||
|
||||
<div className="relative py-24">
|
||||
<div className="absolute inset-0 z-0">
|
||||
<div className="grid grid-cols-12 h-full">
|
||||
{Array(12)
|
||||
.fill(null)
|
||||
.map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="border-l border-dashed border-stone-100 dark:border-white/10 h-full"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="grid grid-rows-12 w-full absolute top-0">
|
||||
{Array(12)
|
||||
.fill(null)
|
||||
.map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="border-t border-dashed border-stone-100 dark:border-stone-900/60 w-full"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-6xl mx-auto px-6 relative z-10">
|
||||
<h2 className="text-3xl font-bold mb-12 font-geist text-center">
|
||||
What does V1 means?
|
||||
</h2>
|
||||
<p>
|
||||
Hey there! Thanks for stopping by. Since announcing Better Auth,
|
||||
your excitement has been incredibly motivating—thank you! <br />
|
||||
<br />
|
||||
V1 is an important milestone for us, but it simply means we believe
|
||||
you can use it in production. We'll continue improving, adding new
|
||||
features, and fixing bugs at the same pace as before. While we
|
||||
strive to make this version as stable and secure as possible, we
|
||||
don't expect it to be perfect. <br /> <br />
|
||||
If you're using Better Auth, we recommend updating to V1 as soon as
|
||||
possible. There are some breaking changes, but join us on{" "}
|
||||
<Link
|
||||
href="https://discord.gg/GYC3W7tZzb"
|
||||
className="underline"
|
||||
target="_blank"
|
||||
>
|
||||
Discord
|
||||
</Link>
|
||||
, and we'll gladly help if you've been using Better Auth in
|
||||
production.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ReleaseRelated />
|
||||
|
||||
{/* <div className="max-w-6xl mx-auto px-6 py-24">
|
||||
<motion.div
|
||||
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
>
|
||||
<FeatureCard
|
||||
icon={<Zap className="w-6 h-6" />}
|
||||
title="Enhanced Performance"
|
||||
description="50% faster load times and optimized resource usage"
|
||||
/>
|
||||
<FeatureCard
|
||||
icon={<Shield className="w-6 h-6" />}
|
||||
title="Advanced Security"
|
||||
description="End-to-end encryption and improved authentication"
|
||||
/>
|
||||
<FeatureCard
|
||||
icon={<GitCommit className="w-6 h-6" />}
|
||||
title="New Architecture"
|
||||
description="Rebuilt from ground up for better scalability"
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="text-center mt-20"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
>
|
||||
<Button
|
||||
size="lg"
|
||||
className="bg-white text-black hover:bg-gray-200 font-medium"
|
||||
>
|
||||
Get Started <ArrowRight className="ml-2 w-4 h-4" />
|
||||
</Button>
|
||||
</motion.div>
|
||||
</div> */}
|
||||
|
||||
<div className="border-t border-white/10">
|
||||
<div className="max-w-4xl mx-auto px-6 py-24">
|
||||
<h2 className="text-3xl font-bold mb-12 font-geist">Changelog</h2>
|
||||
<div className="space-y-8">
|
||||
<ChangelogItem
|
||||
version="1.0.0"
|
||||
date="2024"
|
||||
changes={[
|
||||
"feat: Open API Docs Plugin",
|
||||
"docs: Sign In Box Builder",
|
||||
"fix: Bug fixes and performance improvements",
|
||||
"feat: New server only endpoints for Organization and Two Factor plugins",
|
||||
"refactor: all core tables now have `createdAt` and `updatedAt` fields",
|
||||
"refactor: session id and token are now stored in separate fields",
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ReleaseRelated() {
|
||||
return (
|
||||
<div className="relative dark:bg-transparent/10 bg-zinc-100 border-b-2 border-white/10 rounded-none py-24">
|
||||
<div className="absolute inset-0 z-0">
|
||||
<div className="grid grid-rows-12 w-full absolute top-0">
|
||||
{Array(12)
|
||||
.fill(null)
|
||||
.map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="border-t border-dashed border-white/10 w-full"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-6xl mx-auto px-6 relative z-10">
|
||||
<h2 className="text-7xl font-bold mb-16 font-geist leading-tight">
|
||||
What will you
|
||||
<br />
|
||||
do next?
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold mb-4">Install Latest</h3>
|
||||
<div className="dark:bg-white/5 bg-black/10 rounded-lg p-4 mb-2">
|
||||
<code className="text-sm font-mono">
|
||||
npm i better-auth@latest
|
||||
</code>
|
||||
</div>
|
||||
<p className="text-sm text-gray-400">
|
||||
Get the latest{" "}
|
||||
<a href="#" className="underline">
|
||||
Node.js and npm
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold mb-4">Adopt the new Schema</h3>
|
||||
<div className="dark:bg-white/5 bg-black/10 rounded-lg p-4 mb-2">
|
||||
<code className="text-sm font-mono ">
|
||||
pnpx @better-auth/cli migrate
|
||||
<br />
|
||||
</code>
|
||||
</div>
|
||||
<p className="text-sm text-gray-400">
|
||||
Ensure you have the latest{" "}
|
||||
<code className="text-xs dark:bg-white/5 bg-black/10 px-1 py-0.5 rounded">
|
||||
schema required
|
||||
</code>{" "}
|
||||
by Better Auth.
|
||||
<code className="text-xs dark:bg-white/5 bg-black/10 px-1 py-0.5 rounded">
|
||||
You can also
|
||||
</code>{" "}
|
||||
add them manually. Read the{" "}
|
||||
<a
|
||||
href="/docs/concepts/database#core-schema"
|
||||
className="underline"
|
||||
>
|
||||
Core Schema
|
||||
</a>{" "}
|
||||
for full instructions.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold mb-4">
|
||||
Check out the change log, the new UI Builder, OpenAPI Docs, and ⭐
|
||||
on GitHub (if you haven't already)
|
||||
</h3>
|
||||
<p className="text-sm text-gray-400 mb-4">
|
||||
We have some exciting new features and updates that you should
|
||||
check out.
|
||||
</p>
|
||||
<Button variant="outline" className="w-full justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<GitHubLogoIcon fontSize={10} />
|
||||
Star on GitHub
|
||||
</div>
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full justify-between border-t-0"
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<DiscordLogoIcon />
|
||||
Join Discord
|
||||
</div>
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FeatureCard({
|
||||
icon,
|
||||
title,
|
||||
description,
|
||||
}: { icon: ReactNode; title: string; description: string }) {
|
||||
return (
|
||||
<div className="p-6 rounded-none border border-white/10 bg-white/5 hover:bg-white/10 transition-colors">
|
||||
<div className="w-12 h-12 rounded-full bg-white/10 flex items-center justify-center mb-4">
|
||||
{icon}
|
||||
</div>
|
||||
<h3 className="text-xl font-bold mb-2 font-geist">{title}</h3>
|
||||
<p className="text-gray-400">{description}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ChangelogItem({
|
||||
version,
|
||||
date,
|
||||
changes,
|
||||
}: { version: string; date: string; changes: string[] }) {
|
||||
return (
|
||||
<div className="border-l-2 border-white/10 pl-6 relative">
|
||||
<div className="absolute w-3 h-3 bg-white rounded-full -left-[7px] top-2" />
|
||||
<div className="flex items-center gap-4 mb-4">
|
||||
<h3 className="text-xl font-bold font-geist">{version}</h3>
|
||||
<span className="text-sm text-gray-400">{date}</span>
|
||||
</div>
|
||||
<ul className="space-y-3">
|
||||
{changes.map((change, i) => (
|
||||
<li key={i} className="text-gray-400">
|
||||
{change}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ChangeCard({
|
||||
title,
|
||||
description,
|
||||
}: { title: string; description: string }) {
|
||||
return (
|
||||
<Card className="bg-white/5 rounded-none border-white/10 hover:bg-white/10 transition-colors">
|
||||
<div className="p-6">
|
||||
<h3 className="text-xl font-bold mb-2 font-geist-mono">{title}</h3>
|
||||
<p className="text-gray-400 font-geist-mono">{description}</p>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ export const PulicBetaBadge = ({ text }: { text?: string }) => {
|
||||
<div className="flex flex-col">
|
||||
<div className={badgestyle.beta}>
|
||||
<span className={badgestyle.top_key}></span>
|
||||
<span className={badgestyle.text}>{text || "BETA"}</span>
|
||||
<span className={badgestyle.text}>{text}</span>
|
||||
<span className={badgestyle.bottom_key_1}></span>
|
||||
<span className={badgestyle.bottom_key_2}></span>
|
||||
</div>
|
||||
@@ -20,7 +20,9 @@ export const PulicBetaBadge = ({ text }: { text?: string }) => {
|
||||
d="M13 4V2c4.66.5 8.33 4.19 8.85 8.85c.6 5.49-3.35 10.43-8.85 11.03v-2c3.64-.45 6.5-3.32 6.96-6.96A7.994 7.994 0 0 0 13 4m-7.33.2A9.8 9.8 0 0 1 11 2v2.06c-1.43.2-2.78.78-3.9 1.68zM2.05 11a9.8 9.8 0 0 1 2.21-5.33L5.69 7.1A8 8 0 0 0 4.05 11zm2.22 7.33A10.04 10.04 0 0 1 2.06 13h2c.18 1.42.75 2.77 1.63 3.9zm1.4 1.41l1.39-1.37h.04c1.13.88 2.48 1.45 3.9 1.63v2c-1.96-.21-3.82-1-5.33-2.26M12 17l1.56-3.42L17 12l-3.44-1.56L12 7l-1.57 3.44L7 12l3.43 1.58z"
|
||||
></path>
|
||||
</svg>
|
||||
<span className="text-xs text-opacity-75">v1 - nov. 22</span>
|
||||
<span className="text-xs text-opacity-75">
|
||||
Own Your Auth
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
141
docs/components/builder/beam.tsx
Normal file
141
docs/components/builder/beam.tsx
Normal file
@@ -0,0 +1,141 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export const BackgroundBeams = React.memo(
|
||||
({ className }: { className?: string }) => {
|
||||
const paths = [
|
||||
"M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875",
|
||||
"M-373 -197C-373 -197 -305 208 159 335C623 462 691 867 691 867",
|
||||
"M-366 -205C-366 -205 -298 200 166 327C630 454 698 859 698 859",
|
||||
"M-359 -213C-359 -213 -291 192 173 319C637 446 705 851 705 851",
|
||||
"M-352 -221C-352 -221 -284 184 180 311C644 438 712 843 712 843",
|
||||
"M-345 -229C-345 -229 -277 176 187 303C651 430 719 835 719 835",
|
||||
"M-338 -237C-338 -237 -270 168 194 295C658 422 726 827 726 827",
|
||||
"M-331 -245C-331 -245 -263 160 201 287C665 414 733 819 733 819",
|
||||
"M-324 -253C-324 -253 -256 152 208 279C672 406 740 811 740 811",
|
||||
"M-317 -261C-317 -261 -249 144 215 271C679 398 747 803 747 803",
|
||||
"M-310 -269C-310 -269 -242 136 222 263C686 390 754 795 754 795",
|
||||
"M-303 -277C-303 -277 -235 128 229 255C693 382 761 787 761 787",
|
||||
"M-296 -285C-296 -285 -228 120 236 247C700 374 768 779 768 779",
|
||||
"M-289 -293C-289 -293 -221 112 243 239C707 366 775 771 775 771",
|
||||
"M-282 -301C-282 -301 -214 104 250 231C714 358 782 763 782 763",
|
||||
"M-275 -309C-275 -309 -207 96 257 223C721 350 789 755 789 755",
|
||||
"M-268 -317C-268 -317 -200 88 264 215C728 342 796 747 796 747",
|
||||
"M-261 -325C-261 -325 -193 80 271 207C735 334 803 739 803 739",
|
||||
"M-254 -333C-254 -333 -186 72 278 199C742 326 810 731 810 731",
|
||||
"M-247 -341C-247 -341 -179 64 285 191C749 318 817 723 817 723",
|
||||
"M-240 -349C-240 -349 -172 56 292 183C756 310 824 715 824 715",
|
||||
"M-233 -357C-233 -357 -165 48 299 175C763 302 831 707 831 707",
|
||||
"M-226 -365C-226 -365 -158 40 306 167C770 294 838 699 838 699",
|
||||
"M-219 -373C-219 -373 -151 32 313 159C777 286 845 691 845 691",
|
||||
"M-212 -381C-212 -381 -144 24 320 151C784 278 852 683 852 683",
|
||||
"M-205 -389C-205 -389 -137 16 327 143C791 270 859 675 859 675",
|
||||
"M-198 -397C-198 -397 -130 8 334 135C798 262 866 667 866 667",
|
||||
"M-191 -405C-191 -405 -123 0 341 127C805 254 873 659 873 659",
|
||||
"M-184 -413C-184 -413 -116 -8 348 119C812 246 880 651 880 651",
|
||||
"M-177 -421C-177 -421 -109 -16 355 111C819 238 887 643 887 643",
|
||||
"M-170 -429C-170 -429 -102 -24 362 103C826 230 894 635 894 635",
|
||||
"M-163 -437C-163 -437 -95 -32 369 95C833 222 901 627 901 627",
|
||||
"M-156 -445C-156 -445 -88 -40 376 87C840 214 908 619 908 619",
|
||||
"M-149 -453C-149 -453 -81 -48 383 79C847 206 915 611 915 611",
|
||||
"M-142 -461C-142 -461 -74 -56 390 71C854 198 922 603 922 603",
|
||||
"M-135 -469C-135 -469 -67 -64 397 63C861 190 929 595 929 595",
|
||||
"M-128 -477C-128 -477 -60 -72 404 55C868 182 936 587 936 587",
|
||||
"M-121 -485C-121 -485 -53 -80 411 47C875 174 943 579 943 579",
|
||||
"M-114 -493C-114 -493 -46 -88 418 39C882 166 950 571 950 571",
|
||||
"M-107 -501C-107 -501 -39 -96 425 31C889 158 957 563 957 563",
|
||||
"M-100 -509C-100 -509 -32 -104 432 23C896 150 964 555 964 555",
|
||||
"M-93 -517C-93 -517 -25 -112 439 15C903 142 971 547 971 547",
|
||||
"M-86 -525C-86 -525 -18 -120 446 7C910 134 978 539 978 539",
|
||||
"M-79 -533C-79 -533 -11 -128 453 -1C917 126 985 531 985 531",
|
||||
"M-72 -541C-72 -541 -4 -136 460 -9C924 118 992 523 992 523",
|
||||
"M-65 -549C-65 -549 3 -144 467 -17C931 110 999 515 999 515",
|
||||
"M-58 -557C-58 -557 10 -152 474 -25C938 102 1006 507 1006 507",
|
||||
"M-51 -565C-51 -565 17 -160 481 -33C945 94 1013 499 1013 499",
|
||||
"M-44 -573C-44 -573 24 -168 488 -41C952 86 1020 491 1020 491",
|
||||
"M-37 -581C-37 -581 31 -176 495 -49C959 78 1027 483 1027 483",
|
||||
];
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute h-full w-full inset-0 [mask-size:40px] [mask-repeat:no-repeat] flex items-center justify-center",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<svg
|
||||
className=" z-0 h-full w-full pointer-events-none absolute "
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 696 316"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M-380 -189C-380 -189 -312 216 152 343C616 470 684 875 684 875M-373 -197C-373 -197 -305 208 159 335C623 462 691 867 691 867M-366 -205C-366 -205 -298 200 166 327C630 454 698 859 698 859M-359 -213C-359 -213 -291 192 173 319C637 446 705 851 705 851M-352 -221C-352 -221 -284 184 180 311C644 438 712 843 712 843M-345 -229C-345 -229 -277 176 187 303C651 430 719 835 719 835M-338 -237C-338 -237 -270 168 194 295C658 422 726 827 726 827M-331 -245C-331 -245 -263 160 201 287C665 414 733 819 733 819M-324 -253C-324 -253 -256 152 208 279C672 406 740 811 740 811M-317 -261C-317 -261 -249 144 215 271C679 398 747 803 747 803M-310 -269C-310 -269 -242 136 222 263C686 390 754 795 754 795M-303 -277C-303 -277 -235 128 229 255C693 382 761 787 761 787M-296 -285C-296 -285 -228 120 236 247C700 374 768 779 768 779M-289 -293C-289 -293 -221 112 243 239C707 366 775 771 775 771M-282 -301C-282 -301 -214 104 250 231C714 358 782 763 782 763M-275 -309C-275 -309 -207 96 257 223C721 350 789 755 789 755M-268 -317C-268 -317 -200 88 264 215C728 342 796 747 796 747M-261 -325C-261 -325 -193 80 271 207C735 334 803 739 803 739M-254 -333C-254 -333 -186 72 278 199C742 326 810 731 810 731M-247 -341C-247 -341 -179 64 285 191C749 318 817 723 817 723M-240 -349C-240 -349 -172 56 292 183C756 310 824 715 824 715M-233 -357C-233 -357 -165 48 299 175C763 302 831 707 831 707M-226 -365C-226 -365 -158 40 306 167C770 294 838 699 838 699M-219 -373C-219 -373 -151 32 313 159C777 286 845 691 845 691M-212 -381C-212 -381 -144 24 320 151C784 278 852 683 852 683M-205 -389C-205 -389 -137 16 327 143C791 270 859 675 859 675M-198 -397C-198 -397 -130 8 334 135C798 262 866 667 866 667M-191 -405C-191 -405 -123 0 341 127C805 254 873 659 873 659M-184 -413C-184 -413 -116 -8 348 119C812 246 880 651 880 651M-177 -421C-177 -421 -109 -16 355 111C819 238 887 643 887 643M-170 -429C-170 -429 -102 -24 362 103C826 230 894 635 894 635M-163 -437C-163 -437 -95 -32 369 95C833 222 901 627 901 627M-156 -445C-156 -445 -88 -40 376 87C840 214 908 619 908 619M-149 -453C-149 -453 -81 -48 383 79C847 206 915 611 915 611M-142 -461C-142 -461 -74 -56 390 71C854 198 922 603 922 603M-135 -469C-135 -469 -67 -64 397 63C861 190 929 595 929 595M-128 -477C-128 -477 -60 -72 404 55C868 182 936 587 936 587M-121 -485C-121 -485 -53 -80 411 47C875 174 943 579 943 579M-114 -493C-114 -493 -46 -88 418 39C882 166 950 571 950 571M-107 -501C-107 -501 -39 -96 425 31C889 158 957 563 957 563M-100 -509C-100 -509 -32 -104 432 23C896 150 964 555 964 555M-93 -517C-93 -517 -25 -112 439 15C903 142 971 547 971 547M-86 -525C-86 -525 -18 -120 446 7C910 134 978 539 978 539M-79 -533C-79 -533 -11 -128 453 -1C917 126 985 531 985 531M-72 -541C-72 -541 -4 -136 460 -9C924 118 992 523 992 523M-65 -549C-65 -549 3 -144 467 -17C931 110 999 515 999 515M-58 -557C-58 -557 10 -152 474 -25C938 102 1006 507 1006 507M-51 -565C-51 -565 17 -160 481 -33C945 94 1013 499 1013 499M-44 -573C-44 -573 24 -168 488 -41C952 86 1020 491 1020 491M-37 -581C-37 -581 31 -176 495 -49C959 78 1027 483 1027 483M-30 -589C-30 -589 38 -184 502 -57C966 70 1034 475 1034 475M-23 -597C-23 -597 45 -192 509 -65C973 62 1041 467 1041 467M-16 -605C-16 -605 52 -200 516 -73C980 54 1048 459 1048 459M-9 -613C-9 -613 59 -208 523 -81C987 46 1055 451 1055 451M-2 -621C-2 -621 66 -216 530 -89C994 38 1062 443 1062 443M5 -629C5 -629 73 -224 537 -97C1001 30 1069 435 1069 435M12 -637C12 -637 80 -232 544 -105C1008 22 1076 427 1076 427M19 -645C19 -645 87 -240 551 -113C1015 14 1083 419 1083 419"
|
||||
stroke="url(#paint0_radial_242_278)"
|
||||
strokeOpacity="0.05"
|
||||
strokeWidth="0.5"
|
||||
></path>
|
||||
|
||||
{paths.map((path, index) => (
|
||||
<motion.path
|
||||
key={`path-` + index}
|
||||
d={path}
|
||||
stroke={`url(#linearGradient-${index})`}
|
||||
strokeOpacity="0.4"
|
||||
strokeWidth="0.5"
|
||||
></motion.path>
|
||||
))}
|
||||
<defs>
|
||||
{paths.map((path, index) => (
|
||||
<motion.linearGradient
|
||||
id={`linearGradient-${index}`}
|
||||
key={`gradient-${index}`}
|
||||
initial={{
|
||||
x1: "0%",
|
||||
x2: "0%",
|
||||
y1: "0%",
|
||||
y2: "0%",
|
||||
}}
|
||||
animate={{
|
||||
x1: ["0%", "100%"],
|
||||
x2: ["0%", "95%"],
|
||||
y1: ["0%", "100%"],
|
||||
y2: ["0%", `${93 + Math.random() * 8}%`],
|
||||
}}
|
||||
transition={{
|
||||
duration: Math.random() * 10 + 10,
|
||||
ease: "easeInOut",
|
||||
repeat: Infinity,
|
||||
delay: Math.random() * 10,
|
||||
}}
|
||||
>
|
||||
<stop stopColor="#18CCFC" stopOpacity="0"></stop>
|
||||
<stop stopColor="#18CCFC"></stop>
|
||||
<stop offset="32.5%" stopColor="#6344F5"></stop>
|
||||
<stop offset="100%" stopColor="#AE48FF" stopOpacity="0"></stop>
|
||||
</motion.linearGradient>
|
||||
))}
|
||||
|
||||
<radialGradient
|
||||
id="paint0_radial_242_278"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(352 34) rotate(90) scale(555 1560.62)"
|
||||
>
|
||||
<stop offset="0.0666667" stopColor="var(--neutral-300)"></stop>
|
||||
<stop offset="0.243243" stopColor="var(--neutral-300)"></stop>
|
||||
<stop offset="0.43594" stopColor="white" stopOpacity="0"></stop>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
BackgroundBeams.displayName = "BackgroundBeams";
|
||||
61
docs/components/builder/code-tabs/code-editor.tsx
Normal file
61
docs/components/builder/code-tabs/code-editor.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { Highlight, themes } from "prism-react-renderer";
|
||||
import { Check, Copy } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import theme from "./theme";
|
||||
|
||||
interface CodeEditorProps {
|
||||
code: string;
|
||||
language: string;
|
||||
}
|
||||
|
||||
export function CodeEditor({ code, language }: CodeEditorProps) {
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
const copyToClipboard = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(code);
|
||||
setIsCopied(true);
|
||||
setTimeout(() => setIsCopied(false), 2000);
|
||||
} catch (err) {
|
||||
console.error("Failed to copy text: ", err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<Highlight theme={theme} code={code} language={language}>
|
||||
{({ className, style, tokens, getLineProps, getTokenProps }) => (
|
||||
<pre
|
||||
className={`${className} p-4 overflow-auto max-h-[400px] rounded-md`}
|
||||
style={style}
|
||||
>
|
||||
{tokens.map((line, i) => (
|
||||
<div key={i} {...getLineProps({ line, key: i })}>
|
||||
<span className="mr-4 text-gray-500 select-none">{i + 1}</span>
|
||||
{line.map((token, key) => (
|
||||
<span key={key} {...getTokenProps({ token, key })} />
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</pre>
|
||||
)}
|
||||
</Highlight>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="absolute top-2 right-2"
|
||||
onClick={copyToClipboard}
|
||||
aria-label="Copy code"
|
||||
>
|
||||
{isCopied ? (
|
||||
<Check className="h-4 w-4" />
|
||||
) : (
|
||||
<Copy className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
55
docs/components/builder/code-tabs/code-tabs.tsx
Normal file
55
docs/components/builder/code-tabs/code-tabs.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
interface TabProps {
|
||||
fileName: string;
|
||||
isActive: boolean;
|
||||
brightnessLevel?: number; // New optional prop for brightness level
|
||||
onClick: () => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const brightnessLevels = [
|
||||
"bg-background",
|
||||
"bg-background-200", //
|
||||
"bg-background-300",
|
||||
"bg-background-400",
|
||||
"bg-background-500",
|
||||
"bg-background-600",
|
||||
"bg-background-700",
|
||||
];
|
||||
|
||||
export function CodeTab({
|
||||
fileName,
|
||||
isActive,
|
||||
brightnessLevel = 0,
|
||||
onClick,
|
||||
onClose,
|
||||
}: TabProps) {
|
||||
const activeBrightnessClass = isActive
|
||||
? brightnessLevels[brightnessLevel % brightnessLevels.length]
|
||||
: "bg-muted";
|
||||
|
||||
const textColor = isActive ? "text-foreground" : "text-muted-foreground";
|
||||
const borderColor = isActive
|
||||
? "border-t-foreground"
|
||||
: "border-t-transparent hover:bg-background/50";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center px-3 py-2 text-sm font-medium border-t-2 cursor-pointer transition-colors duration-200",
|
||||
activeBrightnessClass,
|
||||
textColor,
|
||||
borderColor,
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<span className="truncate max-w-[100px]">{fileName}</span>
|
||||
<button className="ml-2 text-muted-foreground hover:text-foreground transition-colors duration-200">
|
||||
<X size={14} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
147
docs/components/builder/code-tabs/index.tsx
Normal file
147
docs/components/builder/code-tabs/index.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import React, { useState } from "react";
|
||||
import { TabBar } from "./tab-bar";
|
||||
import { CodeEditor } from "./code-editor";
|
||||
import { useAtom } from "jotai";
|
||||
import { optionsAtom } from "../store";
|
||||
import { js_beautify } from "js-beautify";
|
||||
import { singUpString } from "../sign-up";
|
||||
import { signInString } from "../sign-in";
|
||||
|
||||
export default function CodeTabs() {
|
||||
const [options] = useAtom(optionsAtom);
|
||||
|
||||
const initialFiles = [
|
||||
{
|
||||
id: "1",
|
||||
name: "auth.ts",
|
||||
content: `import { betterAuth } from 'better-auth';
|
||||
|
||||
export const auth = betterAuth({
|
||||
${
|
||||
options.email
|
||||
? `emailAndPassword: {
|
||||
enabled: true,
|
||||
${
|
||||
options.forgetPassword
|
||||
? `async sendResetPassword(data, request) {
|
||||
// Send an email to the user with a link to reset their password
|
||||
},`
|
||||
: ``
|
||||
}
|
||||
},`
|
||||
: ""
|
||||
}${
|
||||
options.socialProviders.length
|
||||
? `socialProviders: ${JSON.stringify(
|
||||
options.socialProviders.reduce((acc, provider) => {
|
||||
return {
|
||||
...acc,
|
||||
[provider]: {
|
||||
clientId: `process.env.${provider.toUpperCase()}_CLIENT_ID`,
|
||||
clientSecret: `process.env.${provider.toUpperCase()}_CLIENT_SECRET`,
|
||||
},
|
||||
};
|
||||
}, {}),
|
||||
).replace(/"/g, "")},`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
options.magicLink || options.passkey
|
||||
? `plugins: [
|
||||
${
|
||||
options.magicLink
|
||||
? `magicLink({
|
||||
async sendMagicLink(data) {
|
||||
// Send an email to the user with a magic link
|
||||
},
|
||||
}),`
|
||||
: `${options.passkey ? `passkey(),` : ""}`
|
||||
}
|
||||
${options.passkey && options.magicLink ? `passkey(),` : ""}
|
||||
]`
|
||||
: ""
|
||||
}
|
||||
/** if no database is provided, the user data will be stored in memory.
|
||||
* Make sure to provide a database to persist user data **/
|
||||
});
|
||||
`,
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "auth-client.ts",
|
||||
content: `import { createAuthClient } from "better-auth/react";
|
||||
${
|
||||
options.magicLink || options.passkey
|
||||
? `import { ${options.magicLink ? "magicLinkClient, " : ""}, ${
|
||||
options.passkey ? "passkeyClient" : ""
|
||||
} } from "better-auth/client/plugins";`
|
||||
: ""
|
||||
}
|
||||
|
||||
export const authClient = createAuthClient({
|
||||
baseURL: process.env.NEXT_PUBLIC_APP_URL,
|
||||
${
|
||||
options.magicLink || options.passkey
|
||||
? `plugins: [${options.magicLink ? `magicLinkClient(),` : ""}${
|
||||
options.passkey ? `passkeyClient(),` : ""
|
||||
}],`
|
||||
: ""
|
||||
}
|
||||
})
|
||||
|
||||
export const { signIn, signOut, signUp, useSession } = authClient;
|
||||
`,
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "sign-in.tsx",
|
||||
content: signInString(options),
|
||||
},
|
||||
];
|
||||
if (options.email) {
|
||||
initialFiles.push({
|
||||
id: "4",
|
||||
name: "sign-up.tsx",
|
||||
content: singUpString,
|
||||
});
|
||||
}
|
||||
|
||||
const [files, setFiles] = useState(initialFiles);
|
||||
const [activeFileId, setActiveFileId] = useState(files[0].id);
|
||||
|
||||
const handleTabClick = (fileId: string) => {
|
||||
setActiveFileId(fileId);
|
||||
};
|
||||
|
||||
const handleTabClose = (fileId: string) => {
|
||||
setFiles(files.filter((file) => file.id !== fileId));
|
||||
if (activeFileId === fileId) {
|
||||
setActiveFileId(files[0].id);
|
||||
}
|
||||
};
|
||||
|
||||
const activeFile = files.find((file) => file.id === activeFileId);
|
||||
|
||||
return (
|
||||
<div className="w-full max-w-3xl mx-auto mt-8 border border-border rounded-md overflow-hidden">
|
||||
<TabBar
|
||||
files={files}
|
||||
activeFileId={activeFileId}
|
||||
onTabClick={handleTabClick}
|
||||
onTabClose={handleTabClose}
|
||||
/>
|
||||
<div className="bg-background">
|
||||
{activeFile && (
|
||||
<CodeEditor
|
||||
language="typescript"
|
||||
code={
|
||||
activeFile.name.endsWith(".ts")
|
||||
? js_beautify(activeFile.content)
|
||||
: activeFile.content.replace(/\n{3,}/g, "\n\n")
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
36
docs/components/builder/code-tabs/tab-bar.tsx
Normal file
36
docs/components/builder/code-tabs/tab-bar.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from "react";
|
||||
import { CodeTab } from "./code-tabs";
|
||||
|
||||
interface File {
|
||||
id: string;
|
||||
name: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface TabBarProps {
|
||||
files: File[];
|
||||
activeFileId: string;
|
||||
onTabClick: (fileId: string) => void;
|
||||
onTabClose: (fileId: string) => void;
|
||||
}
|
||||
|
||||
export function TabBar({
|
||||
files,
|
||||
activeFileId,
|
||||
onTabClick,
|
||||
onTabClose,
|
||||
}: TabBarProps) {
|
||||
return (
|
||||
<div className="flex bg-muted border-b border-border">
|
||||
{files.map((file) => (
|
||||
<CodeTab
|
||||
key={file.id}
|
||||
fileName={file.name}
|
||||
isActive={file.id === activeFileId}
|
||||
onClick={() => onTabClick(file.id)}
|
||||
onClose={() => onTabClose(file.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
79
docs/components/builder/code-tabs/theme.ts
Normal file
79
docs/components/builder/code-tabs/theme.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { PrismTheme } from "prism-react-renderer";
|
||||
|
||||
const theme: PrismTheme = {
|
||||
plain: {
|
||||
color: "#d0d0d0",
|
||||
backgroundColor: "#000000", // Changed to true black
|
||||
},
|
||||
styles: [
|
||||
{
|
||||
types: ["comment", "prolog", "doctype", "cdata"],
|
||||
style: {
|
||||
color: "#555555",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["namespace"],
|
||||
style: {
|
||||
opacity: 0.7,
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["string", "attr-value"],
|
||||
style: {
|
||||
color: "#8ab4f8", // Darker soft blue for strings
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["punctuation", "operator"],
|
||||
style: {
|
||||
color: "#888888",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: [
|
||||
"entity",
|
||||
"url",
|
||||
"symbol",
|
||||
"number",
|
||||
"boolean",
|
||||
"variable",
|
||||
"constant",
|
||||
"property",
|
||||
"regex",
|
||||
"inserted",
|
||||
],
|
||||
style: {
|
||||
color: "#a0a0a0",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["atrule", "keyword", "attr-name", "selector"],
|
||||
style: {
|
||||
color: "#c5c5c5",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["function", "deleted", "tag"],
|
||||
style: {
|
||||
color: "#7aa2f7", // Darker soft blue for functions
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["function-variable"],
|
||||
style: {
|
||||
color: "#9e9e9e",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["tag", "selector", "keyword"],
|
||||
style: {
|
||||
color: "#cccccc", // Adjusted to a slightly lighter gray for better contrast on true black
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default theme;
|
||||
576
docs/components/builder/index.tsx
Normal file
576
docs/components/builder/index.tsx
Normal file
@@ -0,0 +1,576 @@
|
||||
import { ChevronLeft, Copy, Mail, Moon, PlusIcon, Sun } from "lucide-react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../ui/dialog";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../ui/card";
|
||||
import SignIn from "./sign-in";
|
||||
import { SignUp } from "./sign-up";
|
||||
import { AuthTabs } from "./tabs";
|
||||
import { Label } from "../ui/label";
|
||||
import { Switch } from "../ui/switch";
|
||||
import { Separator } from "../ui/separator";
|
||||
import { useState } from "react";
|
||||
import CodeTabs from "./code-tabs";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { socialProviders } from "./social-provider";
|
||||
import { useAtom } from "jotai";
|
||||
import { optionsAtom } from "./store";
|
||||
import { useTheme } from "next-themes";
|
||||
import { ScrollArea } from "../ui/scroll-area";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
const frameworks = [
|
||||
{
|
||||
title: "Next.js",
|
||||
description: "The React Framework for Production",
|
||||
Icon: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="2em"
|
||||
height="2em"
|
||||
viewBox="0 0 15 15"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M0 7.5a7.5 7.5 0 1 1 11.698 6.216L4.906 4.21A.5.5 0 0 0 4 4.5V12h1V6.06l5.83 8.162A7.5 7.5 0 0 1 0 7.5M10 10V4h1v6z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Nuxt",
|
||||
description: "The Intuitive Vue Framework",
|
||||
Icon: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="2em"
|
||||
height="2em"
|
||||
viewBox="0 0 256 256"
|
||||
>
|
||||
<g fill="none">
|
||||
<rect width="256" height="256" fill="#242938" rx="60"></rect>
|
||||
<path
|
||||
fill="#00DC82"
|
||||
d="M138.787 189.333h68.772c2.184.001 4.33-.569 6.222-1.652a12.4 12.4 0 0 0 4.554-4.515a12.24 12.24 0 0 0-.006-12.332l-46.185-79.286a12.4 12.4 0 0 0-4.553-4.514a12.53 12.53 0 0 0-12.442 0a12.4 12.4 0 0 0-4.553 4.514l-11.809 20.287l-23.09-39.67a12.4 12.4 0 0 0-4.555-4.513a12.54 12.54 0 0 0-12.444 0a12.4 12.4 0 0 0-4.555 4.513L36.67 170.834a12.24 12.24 0 0 0-.005 12.332a12.4 12.4 0 0 0 4.554 4.515a12.5 12.5 0 0 0 6.222 1.652h43.17c17.104 0 29.718-7.446 38.397-21.973l21.072-36.169l11.287-19.356l33.873 58.142h-45.16zm-48.88-19.376l-30.127-.007l45.16-77.518l22.533 38.759l-15.087 25.906c-5.764 9.426-12.312 12.86-22.48 12.86"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Svelte Kit",
|
||||
description: "Web development for the rest of us",
|
||||
Icon: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="2em"
|
||||
height="2em"
|
||||
viewBox="0 0 256 256"
|
||||
>
|
||||
<g fill="none">
|
||||
<rect width="256" height="256" fill="#FF3E00" rx="60"></rect>
|
||||
<g clipPath="url(#skillIconsSvelte0)">
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M193.034 61.797c-16.627-23.95-49.729-30.966-73.525-15.865L77.559 72.78c-11.44 7.17-19.372 18.915-21.66 32.186c-1.984 11.136-.306 22.576 5.033 32.492c-3.66 5.491-6.102 11.593-7.17 18c-2.44 13.576.764 27.61 8.696 38.745c16.78 23.95 49.728 30.966 73.525 15.865l41.949-26.695c11.441-7.17 19.373-18.915 21.661-32.187c1.983-11.135.305-22.576-5.034-32.491c3.661-5.492 6.102-11.593 7.17-18c2.593-13.729-.61-27.763-8.695-38.898"
|
||||
></path>
|
||||
<path
|
||||
fill="#FF3E00"
|
||||
d="M115.39 196.491a33.25 33.25 0 0 1-35.695-13.271c-4.881-6.712-6.712-15.101-5.34-23.339c.306-1.373.611-2.593.916-3.966l.763-2.44L78.169 155a55.6 55.6 0 0 0 16.475 8.237l1.525.458l-.152 1.525c-.153 2.136.458 4.424 1.678 6.255c2.441 3.508 6.712 5.186 10.83 4.118c.916-.305 1.831-.61 2.594-1.068l41.796-26.695c2.136-1.372 3.509-3.355 3.966-5.796s-.152-5.034-1.525-7.017c-2.441-3.509-6.712-5.034-10.831-3.966c-.915.305-1.83.61-2.593 1.068l-16.017 10.22c-2.593 1.678-5.491 2.898-8.542 3.661a33.25 33.25 0 0 1-35.695-13.271c-4.729-6.712-6.712-15.102-5.186-23.339c1.372-7.932 6.254-15.102 13.118-19.373l41.949-26.695c2.593-1.678 5.492-2.898 8.543-3.814a33.25 33.25 0 0 1 35.695 13.272c4.881 6.712 6.711 15.101 5.339 23.339c-.306 1.373-.611 2.593-1.068 3.966l-.763 2.44l-2.136-1.525a55.6 55.6 0 0 0-16.474-8.237l-1.526-.458l.153-1.525c.153-2.136-.458-4.424-1.678-6.255c-2.441-3.508-6.712-5.034-10.83-3.966c-.916.305-1.831.61-2.594 1.068l-41.796 26.695c-2.136 1.373-3.509 3.356-3.966 5.797s.152 5.034 1.525 7.017c2.441 3.508 6.712 5.033 10.831 3.966c.915-.305 1.83-.611 2.593-1.068l16.017-10.22c2.593-1.678 5.491-2.899 8.542-3.814a33.25 33.25 0 0 1 35.695 13.271c4.881 6.712 6.712 15.102 5.339 23.339c-1.373 7.932-6.254 15.102-13.119 19.373l-41.949 26.695c-2.593 1.678-5.491 2.898-8.542 3.813"
|
||||
></path>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="skillIconsSvelte0">
|
||||
<path fill="#fff" d="M53 38h149.644v180H53z"></path>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</g>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Solid Start",
|
||||
description: "Fine-grained reactivity goes fullstack",
|
||||
Icon: () => (
|
||||
<svg
|
||||
data-hk="00000010210"
|
||||
width="2em"
|
||||
height="2em"
|
||||
viewBox="0 0 500 500"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
role="presentation"
|
||||
>
|
||||
<path
|
||||
d="M233.205 430.856L304.742 425.279C304.742 425.279 329.208 421.295 343.569 397.659L293.041 385.443L233.205 430.856Z"
|
||||
fill="url(#paint0_linear_1_2)"
|
||||
></path>
|
||||
<path
|
||||
d="M134.278 263.278C113.003 264.341 73.6443 268.059 73.6443 268.059L245.173 392.614L284.265 402.44L343.569 397.925L170.977 273.105C170.977 273.105 157.148 263.278 137.203 263.278C136.139 263.278 135.342 263.278 134.278 263.278Z"
|
||||
fill="url(#paint1_linear_1_2)"
|
||||
></path>
|
||||
<path
|
||||
d="M355.536 238.58L429.2 234.065C429.2 234.065 454.464 230.348 468.825 206.977L416.435 193.964L355.536 238.58Z"
|
||||
fill="url(#paint2_linear_1_2)"
|
||||
></path>
|
||||
<path
|
||||
d="M251.289 68.6128C229.217 69.4095 188.795 72.5964 188.795 72.5964L367.503 200.072L407.926 210.429L469.09 206.712L289.318 78.9702C289.318 78.9702 274.426 68.6128 253.417 68.6128C252.885 68.6128 252.087 68.6128 251.289 68.6128Z"
|
||||
fill="url(#paint3_linear_1_2)"
|
||||
></path>
|
||||
<path
|
||||
d="M31.0946 295.679C30.8287 295.945 30.8287 296.21 30.8287 296.475L77.8993 330.469L202.623 420.764C228.95 439.62 264.586 431.653 282.67 402.44L187.465 333.921L110.077 277.62C100.504 270.715 89.8663 267.528 79.2289 267.528C60.6134 267.528 42.2639 277.354 31.0946 295.679Z"
|
||||
fill="url(#paint4_linear_1_2)"
|
||||
></path>
|
||||
<path
|
||||
d="M147.043 99.9505C147.043 100.216 146.776 100.482 146.511 100.747L195.442 135.538L244.374 170.062L325.751 227.957C353.142 247.345 389.841 239.642 407.925 210.695L358.461 175.374L308.997 140.318L228.153 82.6881C218.047 75.5177 206.611 72.0652 195.442 72.0652C176.561 72.3308 158.212 81.8915 147.043 99.9505Z"
|
||||
fill="url(#paint5_linear_1_2)"
|
||||
></path>
|
||||
<path
|
||||
d="M112.471 139.255L175.497 208.305C178.423 212.289 181.614 216.006 185.337 219.193L308.199 354.105L369.364 350.387C387.448 321.439 380.002 282.135 352.611 262.748L271.234 204.852L222.568 170.328L173.636 135.538L112.471 139.255Z"
|
||||
fill="url(#paint6_linear_1_2)"
|
||||
></path>
|
||||
<path
|
||||
d="M111.939 140.052C94.1213 168.734 101.567 207.509 128.427 226.629L209.005 283.994L258.735 319.049L308.199 354.105C326.283 325.158 318.836 285.852 291.445 266.465L112.471 139.255C112.471 139.521 112.204 139.787 111.939 140.052Z"
|
||||
fill="url(#paint7_linear_1_2)"
|
||||
></path>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_1_2"
|
||||
x1="359.728"
|
||||
y1="56.8062"
|
||||
x2="265.623"
|
||||
y2="521.28"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#1593F5"></stop>
|
||||
<stop offset="1" stopColor="#0084CE"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_1_2"
|
||||
x1="350.496"
|
||||
y1="559.872"
|
||||
x2="-44.0802"
|
||||
y2="-73.2062"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#1593F5"></stop>
|
||||
<stop offset="1" stopColor="#0084CE"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_1_2"
|
||||
x1="610.25"
|
||||
y1="570.526"
|
||||
x2="372.635"
|
||||
y2="144.034"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white"></stop>
|
||||
<stop offset="1" stopColor="#15ABFF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_1_2"
|
||||
x1="188.808"
|
||||
y1="-180.608"
|
||||
x2="390.515"
|
||||
y2="281.703"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white"></stop>
|
||||
<stop offset="1" stopColor="#79CFFF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_1_2"
|
||||
x1="415.84"
|
||||
y1="-4.74684"
|
||||
x2="95.1922"
|
||||
y2="439.83"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#0057E5"></stop>
|
||||
<stop offset="1" stopColor="#0084CE"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_1_2"
|
||||
x1="343.141"
|
||||
y1="-21.5427"
|
||||
x2="242.301"
|
||||
y2="256.708"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white"></stop>
|
||||
<stop offset="1" stopColor="#15ABFF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint6_linear_1_2"
|
||||
x1="469.095"
|
||||
y1="533.421"
|
||||
x2="-37.6939"
|
||||
y2="-135.731"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white"></stop>
|
||||
<stop offset="1" stopColor="#79CFFF"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint7_linear_1_2"
|
||||
x1="380.676"
|
||||
y1="-89.0869"
|
||||
x2="120.669"
|
||||
y2="424.902"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="white"></stop>
|
||||
<stop offset="1" stopColor="#79CFFF"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export function Builder() {
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
|
||||
const [options, setOptions] = useAtom(optionsAtom);
|
||||
const { setTheme, resolvedTheme } = useTheme();
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button className="bg-stone-950 no-underline group cursor-pointer relative shadow-2xl shadow-zinc-900 rounded-sm p-px text-xs font-semibold leading-6 text-white inline-block">
|
||||
<span className="absolute inset-0 overflow-hidden rounded-sm">
|
||||
<span className="absolute inset-0 rounded-sm bg-[image:radial-gradient(75%_100%_at_50%_0%,rgba(56,189,248,0.6)_0%,rgba(56,189,248,0)_75%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100"></span>
|
||||
</span>
|
||||
<div className="relative flex space-x-2 items-center z-10 rounded-none bg-zinc-950 py-2 px-4 ring-1 ring-white/10 ">
|
||||
<PlusIcon size={14} />
|
||||
<span>Create Sign in Box</span>
|
||||
</div>
|
||||
<span className="absolute -bottom-0 left-[1.125rem] h-px w-[calc(100%-2.25rem)] bg-gradient-to-r from-emerald-400/0 via-stone-800/90 to-emerald-400/0 transition-opacity duration-500 group-hover:opacity-40"></span>
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-7xl h-5/6 overflow-clip">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create Sign in Box</DialogTitle>
|
||||
<DialogDescription>
|
||||
Configure the sign in box to your liking and copy the code to your
|
||||
application
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="flex gap-4 md:gap-12 flex-col md:flex-row items-center md:items-start">
|
||||
<ScrollArea className="w-4/12">
|
||||
<div className="overflow-scroll h-[580px] relate">
|
||||
{options.signUp ? (
|
||||
<AuthTabs
|
||||
tabs={[
|
||||
{
|
||||
title: "Sign In",
|
||||
value: "sign-in",
|
||||
content: <SignIn />,
|
||||
},
|
||||
{
|
||||
title: "Sign Up",
|
||||
value: "sign-up",
|
||||
content: <SignUp />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<SignIn />
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<ScrollArea className="w-5/12 flex-grow">
|
||||
<div className="h-[580px]">
|
||||
{currentStep === 0 ? (
|
||||
<Card className="rounded-none flex-grow h-full">
|
||||
<CardHeader className="flex flex-row justify-between">
|
||||
<CardTitle>Configuration</CardTitle>
|
||||
<div
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
if (resolvedTheme === "dark") {
|
||||
setTheme("light");
|
||||
} else {
|
||||
setTheme("dark");
|
||||
}
|
||||
}}
|
||||
>
|
||||
{resolvedTheme === "dark" ? (
|
||||
<Moon onClick={() => setTheme("light")} size={18} />
|
||||
) : (
|
||||
<Sun onClick={() => setTheme("dark")} size={18} />
|
||||
)}
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="max-h-[400px] overflow-scroll">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div>
|
||||
<Label>Email & Password</Label>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<Label>Enabled</Label>
|
||||
</div>
|
||||
<Switch
|
||||
checked={options.email}
|
||||
onCheckedChange={(checked) => {
|
||||
setOptions((prev) => ({
|
||||
...prev,
|
||||
email: checked,
|
||||
magicLink: checked ? false : prev.magicLink,
|
||||
signUp: checked,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label>Remember Me</Label>
|
||||
</div>
|
||||
<Switch
|
||||
checked={options.rememberMe}
|
||||
onCheckedChange={(checked) => {
|
||||
setOptions((prev) => ({
|
||||
...prev,
|
||||
rememberMe: checked,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Label>Forget Password</Label>
|
||||
</div>
|
||||
<Switch
|
||||
checked={options.forgetPassword}
|
||||
onCheckedChange={(checked) => {
|
||||
setOptions((prev) => ({
|
||||
...prev,
|
||||
forgetPassword: checked,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 mt-4">
|
||||
<div>
|
||||
<Label>Social Providers</Label>
|
||||
</div>
|
||||
<Separator />
|
||||
{Object.entries(socialProviders).map(
|
||||
([provider, { Icon }]) => (
|
||||
<div
|
||||
className="flex items-center justify-between"
|
||||
key={provider}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<Icon />
|
||||
<Label>
|
||||
{provider.charAt(0).toUpperCase() +
|
||||
provider.slice(1)}
|
||||
</Label>
|
||||
</div>
|
||||
<Switch
|
||||
checked={options.socialProviders.includes(
|
||||
provider,
|
||||
)}
|
||||
onCheckedChange={(checked) => {
|
||||
setOptions((prev) => ({
|
||||
...prev,
|
||||
socialProviders: checked
|
||||
? [...prev.socialProviders, provider]
|
||||
: prev.socialProviders.filter(
|
||||
(p) => p !== provider,
|
||||
),
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 mt-4">
|
||||
<div>
|
||||
<Label>Plugins</Label>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M5 20q-.825 0-1.412-.587T3 18v-.8q0-.85.438-1.562T4.6 14.55q1.55-.775 3.15-1.162T11 13q.35 0 .7.013t.7.062q.275.025.437.213t.163.462q.05 1.175.575 2.213t1.4 1.762q.175.125.275.313t.1.412V19q0 .425-.288.713T14.35 20zm6-8q-1.65 0-2.825-1.175T7 8t1.175-2.825T11 4t2.825 1.175T15 8t-1.175 2.825T11 12m7.5 2q.425 0 .713-.288T19.5 13t-.288-.712T18.5 12t-.712.288T17.5 13t.288.713t.712.287m.15 8.65l-1-1q-.05-.05-.15-.35v-4.45q-1.1-.325-1.8-1.237T15 13.5q0-1.45 1.025-2.475T18.5 10t2.475 1.025T22 13.5q0 1.125-.638 2t-1.612 1.25l.9.9q.15.15.15.35t-.15.35l-.8.8q-.15.15-.15.35t.15.35l.8.8q.15.15.15.35t-.15.35l-1.3 1.3q-.15.15-.35.15t-.35-.15"
|
||||
></path>
|
||||
</svg>
|
||||
<Label>Passkey</Label>
|
||||
</div>
|
||||
<Switch
|
||||
checked={options.passkey}
|
||||
onCheckedChange={(checked) => {
|
||||
setOptions((prev) => ({
|
||||
...prev,
|
||||
passkey: checked,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<g fill="none">
|
||||
<path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M17.5 3a4.5 4.5 0 0 1 4.495 4.288L22 7.5V15a2 2 0 0 1-1.85 1.995L20 17h-3v3a1 1 0 0 1-1.993.117L15 20v-3H4a2 2 0 0 1-1.995-1.85L2 15V7.5a4.5 4.5 0 0 1 4.288-4.495L6.5 3zm-11 2A2.5 2.5 0 0 0 4 7.5V15h5V7.5A2.5 2.5 0 0 0 6.5 5M7 8a1 1 0 0 1 .117 1.993L7 10H6a1 1 0 0 1-.117-1.993L6 8z"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
<Label>Magic Link</Label>
|
||||
</div>
|
||||
<Switch
|
||||
checked={options.magicLink}
|
||||
onCheckedChange={(checked) => {
|
||||
setOptions((prev) => ({
|
||||
...prev,
|
||||
magicLink: checked,
|
||||
email: checked ? false : prev.email,
|
||||
signUp: checked ? false : prev.signUp,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Separator />
|
||||
<div className="flex items-center justify-between mt-2">
|
||||
<Label>Powered by label</Label>
|
||||
<Switch
|
||||
checked={options.label}
|
||||
onCheckedChange={(checked) => {
|
||||
setOptions((prev) => ({
|
||||
...prev,
|
||||
label: checked,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<button
|
||||
className="bg-stone-950 no-underline group cursor-pointer relative shadow-2xl shadow-zinc-900 rounded-sm p-px text-xs font-semibold leading-6 text-white inline-block w-full"
|
||||
onClick={() => {
|
||||
setCurrentStep(currentStep + 1);
|
||||
}}
|
||||
>
|
||||
<span className="absolute inset-0 overflow-hidden rounded-sm">
|
||||
<span className="absolute inset-0 rounded-sm bg-[image:radial-gradient(75%_100%_at_50%_0%,rgba(56,189,248,0.6)_0%,rgba(56,189,248,0)_75%)] opacity-0 transition-opacity duration-500 group-hover:opacity-100"></span>
|
||||
</span>
|
||||
<div className="relative flex space-x-2 items-center z-10 rounded-none bg-zinc-950 py-2 px-4 ring-1 ring-white/10 justify-center">
|
||||
<span>Continue</span>
|
||||
</div>
|
||||
<span className="absolute -bottom-0 left-[1.125rem] h-px w-[calc(100%-2.25rem)] bg-gradient-to-r from-emerald-400/0 via-stone-800/90 to-emerald-400/0 transition-opacity duration-500 group-hover:opacity-40"></span>
|
||||
</button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
) : currentStep === 1 ? (
|
||||
<Card className="rounded-none flex-grow h-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Choose Framework</CardTitle>
|
||||
<p
|
||||
className="text-blue-400 hover:underline mt-1 text-sm cursor-pointer"
|
||||
onClick={() => {
|
||||
setCurrentStep(0);
|
||||
}}
|
||||
>
|
||||
Go Back
|
||||
</p>
|
||||
</CardHeader>
|
||||
<CardContent className="flex items-start gap-2 flex-wrap justify-between">
|
||||
{frameworks.map((fm) => (
|
||||
<div
|
||||
onClick={() => {
|
||||
if (fm.title === "Next.js") {
|
||||
setCurrentStep(currentStep + 1);
|
||||
}
|
||||
}}
|
||||
className={cn(
|
||||
"flex flex-col items-center gap-4 border p-6 rounded-md w-5/12 flex-grow h-44 relative",
|
||||
fm.title !== "Next.js"
|
||||
? "opacity-55"
|
||||
: "hover:ring-1 transition-all ring-border hover:bg-background duration-200 ease-in-out cursor-pointer",
|
||||
)}
|
||||
key={fm.title}
|
||||
>
|
||||
{fm.title !== "Next.js" && (
|
||||
<span className="absolute top-4 right-4 text-xs">
|
||||
Coming Soon
|
||||
</span>
|
||||
)}
|
||||
<fm.Icon />
|
||||
<Label className="text-2xl">{fm.title}</Label>
|
||||
<p className="text-sm">{fm.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<Card className="rounded-none flex-grow h-full overflow-scroll">
|
||||
<CardHeader>
|
||||
<div className="flex flex-col items-start">
|
||||
<CardTitle>Code</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div>
|
||||
<p>
|
||||
Copy the code below and paste it in your application to
|
||||
get started.
|
||||
</p>
|
||||
<p
|
||||
className="text-blue-400 hover:underline mt-1 text-sm cursor-pointer"
|
||||
onClick={() => {
|
||||
setCurrentStep(0);
|
||||
}}
|
||||
>
|
||||
Go Back
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<CodeTabs />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
406
docs/components/builder/sign-in.tsx
Normal file
406
docs/components/builder/sign-in.tsx
Normal file
@@ -0,0 +1,406 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { DiscordLogoIcon, GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||
import { Key, Loader2 } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { Separator } from "../ui/separator";
|
||||
import { useAtom } from "jotai";
|
||||
import { optionsAtom } from "./store";
|
||||
import { socialProviders } from "./social-provider";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export default function SignIn() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [rememberMe, setRememberMe] = useState(false);
|
||||
const router = useRouter();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [options, setOptions] = useAtom(optionsAtom);
|
||||
return (
|
||||
<Card className="z-50 rounded-none max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg md:text-xl">Sign In</CardTitle>
|
||||
<CardDescription className="text-xs md:text-sm">
|
||||
Enter your email below to login to your account
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4">
|
||||
{options.email && (
|
||||
<>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
}}
|
||||
value={email}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<div className="flex items-center">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
{options.forgetPassword && (
|
||||
<Link
|
||||
href="#"
|
||||
className="ml-auto inline-block text-sm underline"
|
||||
>
|
||||
Forgot your password?
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
placeholder="password"
|
||||
autoComplete="password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{options.rememberMe && (
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
onClick={() => {
|
||||
setRememberMe(!rememberMe);
|
||||
}}
|
||||
/>
|
||||
<Label>Remember me</Label>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{options.magicLink && (
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
}}
|
||||
value={email}
|
||||
/>
|
||||
<Button className="gap-2" onClick={async () => {}}>
|
||||
Sign-in with Magic Link
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{options.email && (
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={loading}
|
||||
onClick={async () => {}}
|
||||
>
|
||||
{loading ? (
|
||||
<Loader2 size={16} className="animate-spin" />
|
||||
) : (
|
||||
"Login"
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{options.passkey && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="gap-2"
|
||||
onClick={async () => {}}
|
||||
>
|
||||
<Key size={16} />
|
||||
Sign-in with Passkey
|
||||
</Button>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"w-full gap-2 flex items-center justify-between",
|
||||
options.socialProviders.length > 3
|
||||
? "flex-row flex-wrap"
|
||||
: "flex-col",
|
||||
)}
|
||||
>
|
||||
{Object.keys(socialProviders).map((provider) => {
|
||||
if (options.socialProviders.includes(provider)) {
|
||||
const { Icon } =
|
||||
socialProviders[provider as keyof typeof socialProviders];
|
||||
return (
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
options.socialProviders.length > 3
|
||||
? "flex-grow"
|
||||
: "w-full gap-2",
|
||||
)}
|
||||
onClick={async () => {}}
|
||||
>
|
||||
<Icon width="1.2em" height="1.2em" />
|
||||
{options.socialProviders.length <= 3 &&
|
||||
"Sign in with " +
|
||||
provider.charAt(0).toUpperCase() +
|
||||
provider.slice(1)}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
{options.label && (
|
||||
<CardFooter>
|
||||
<div className="flex justify-center w-full border-t py-4">
|
||||
<p className="text-center text-xs text-neutral-500">
|
||||
Powered by{" "}
|
||||
<Link
|
||||
href="https://better-auth.com"
|
||||
className="underline"
|
||||
target="_blank"
|
||||
>
|
||||
<span className="dark:text-orange-200/90">better-auth.</span>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</CardFooter>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export const signInString = (options: any) => `"use client"
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useState } from "react";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { signIn } from "@/lib/auth-client";
|
||||
|
||||
function SignInCard() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
return (
|
||||
<Card className="max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg md:text-xl">Sign In</CardTitle>
|
||||
<CardDescription className="text-xs md:text-sm">
|
||||
Enter your email below to login to your account
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4">
|
||||
${
|
||||
options.email
|
||||
? `<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
}}
|
||||
value={email}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-2">
|
||||
<div className="flex items-center">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
${
|
||||
options.forgetPassword
|
||||
? `
|
||||
<Link
|
||||
href="#"
|
||||
className="ml-auto inline-block text-sm underline"
|
||||
>
|
||||
Forgot your password?
|
||||
</Link>
|
||||
`
|
||||
: ``
|
||||
}
|
||||
</div>
|
||||
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
placeholder="password"
|
||||
autoComplete="password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
${
|
||||
options.rememberMe
|
||||
? `<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
onClick={() => {
|
||||
setRememberMe(!rememberMe);
|
||||
}}
|
||||
/>
|
||||
<Label>Remember me</Label>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
${
|
||||
options.magicLink
|
||||
? `
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
}}
|
||||
value={email}
|
||||
/>
|
||||
<Button className="gap-2" onClick={async () => {}}>
|
||||
Sign-in with Magic Link
|
||||
</Button>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
${
|
||||
options.email
|
||||
? `
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={loading}
|
||||
onClick={async () => {
|
||||
await signIn.email({ email, password });
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<Loader2 size={16} className="animate-spin" />
|
||||
) : (
|
||||
"Login"
|
||||
)}
|
||||
</Button>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
|
||||
${
|
||||
options.passkey
|
||||
? `
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="gap-2"
|
||||
onClick={async () => {
|
||||
await sigIn.passkey();
|
||||
}}
|
||||
>
|
||||
<Key size={16} />
|
||||
Sign-in with Passkey
|
||||
</Button>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
options.socialProviders.length > 0
|
||||
? `<div
|
||||
className={cn(
|
||||
${
|
||||
options.socialProviders.length > 3
|
||||
? "w-full gap-2 flex items-center justify-between flex-wrap"
|
||||
: "w-full gap-2 flex items-center justify-between flex-col"
|
||||
},
|
||||
)}
|
||||
>
|
||||
${Object.keys(socialProviders).map((provider) => {
|
||||
if (options.socialProviders.includes(provider)) {
|
||||
const { stringIcon } =
|
||||
socialProviders[provider as keyof typeof socialProviders];
|
||||
return `<Button
|
||||
variant="outline"
|
||||
className={cn(
|
||||
${
|
||||
options.socialProviders.length > 3
|
||||
? "flex-grow"
|
||||
: "w-full gap-2"
|
||||
}
|
||||
)}
|
||||
onClick={async () => {
|
||||
await signIn.social({
|
||||
provider: "${provider}",
|
||||
callbackURL: "/dashboard"
|
||||
});
|
||||
}}
|
||||
>
|
||||
${stringIcon}
|
||||
${
|
||||
options.socialProviders.length <= 3
|
||||
? "Sign in with " +
|
||||
provider.charAt(0).toUpperCase() +
|
||||
provider.slice(1)
|
||||
: ""
|
||||
}
|
||||
</Button>`;
|
||||
}
|
||||
return "";
|
||||
})}
|
||||
</div>`
|
||||
: ""
|
||||
}
|
||||
|
||||
</div>
|
||||
</CardContent>
|
||||
${
|
||||
options.label
|
||||
? `
|
||||
<CardFooter>
|
||||
<div className="flex justify-center w-full border-t py-4">
|
||||
<p className="text-center text-xs text-neutral-500">
|
||||
Powered by{" "}
|
||||
<Link
|
||||
href="https://better-auth.com"
|
||||
className="underline"
|
||||
target="_blank"
|
||||
>
|
||||
<span className="dark:text-orange-200/90">better-auth.</span>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</CardFooter>
|
||||
`
|
||||
: ``
|
||||
}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
`;
|
||||
377
docs/components/builder/sign-up.tsx
Normal file
377
docs/components/builder/sign-up.tsx
Normal file
@@ -0,0 +1,377 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { Loader2, X } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export function SignUp() {
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [passwordConfirmation, setPasswordConfirmation] = useState("");
|
||||
const [image, setImage] = useState<File | null>(null);
|
||||
const [imagePreview, setImagePreview] = useState<string | null>(null);
|
||||
const router = useRouter();
|
||||
|
||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
setImage(file);
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
setImagePreview(reader.result as string);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
};
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
return (
|
||||
<Card className="z-50 rounded-md rounded-t-none max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg md:text-xl">Sign Up</CardTitle>
|
||||
<CardDescription className="text-xs md:text-sm">
|
||||
Enter your information to create an account
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="first-name">First name</Label>
|
||||
<Input
|
||||
id="first-name"
|
||||
placeholder="Max"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setFirstName(e.target.value);
|
||||
}}
|
||||
value={firstName}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="last-name">Last name</Label>
|
||||
<Input
|
||||
id="last-name"
|
||||
placeholder="Robinson"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setLastName(e.target.value);
|
||||
}}
|
||||
value={lastName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
}}
|
||||
value={email}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input
|
||||
id="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
autoComplete="new-password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">Confirm Password</Label>
|
||||
<Input
|
||||
id="password_confirmation"
|
||||
value={passwordConfirmation}
|
||||
onChange={(e) => setPasswordConfirmation(e.target.value)}
|
||||
autoComplete="new-password"
|
||||
placeholder="Confirm Password"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="image">Profile Image (optional)</Label>
|
||||
<div className="flex items-end gap-4">
|
||||
{imagePreview && (
|
||||
<div className="relative w-16 h-16 rounded-sm overflow-hidden">
|
||||
<Image
|
||||
src={imagePreview}
|
||||
alt="Profile preview"
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-2 w-full">
|
||||
<Input
|
||||
id="image"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleImageChange}
|
||||
className="w-full"
|
||||
/>
|
||||
{imagePreview && (
|
||||
<X
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
setImage(null);
|
||||
setImagePreview(null);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={loading}
|
||||
onClick={async () => {}}
|
||||
>
|
||||
{loading ? (
|
||||
<Loader2 size={16} className="animate-spin" />
|
||||
) : (
|
||||
"Create an account"
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="flex justify-center w-full border-t py-4">
|
||||
<p className="text-center text-xs text-neutral-500">
|
||||
Secured by <span className="text-orange-400">better-auth.</span>
|
||||
</p>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
async function convertImageToBase64(file: File): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
export const singUpString = `"use client";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { useState } from "react";
|
||||
import Image from "next/image";
|
||||
import { Loader2, X } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export function SignUp() {
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [passwordConfirmation, setPasswordConfirmation] = useState("");
|
||||
const [image, setImage] = useState<File | null>(null);
|
||||
const [imagePreview, setImagePreview] = useState<string | null>(null);
|
||||
const router = useRouter();
|
||||
|
||||
const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) {
|
||||
setImage(file);
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
setImagePreview(reader.result as string);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
};
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
return (
|
||||
<Card className="z-50 rounded-md rounded-t-none max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg md:text-xl">Sign Up</CardTitle>
|
||||
<CardDescription className="text-xs md:text-sm">
|
||||
Enter your information to create an account
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="first-name">First name</Label>
|
||||
<Input
|
||||
id="first-name"
|
||||
placeholder="Max"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setFirstName(e.target.value);
|
||||
}}
|
||||
value={firstName}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="last-name">Last name</Label>
|
||||
<Input
|
||||
id="last-name"
|
||||
placeholder="Robinson"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setLastName(e.target.value);
|
||||
}}
|
||||
value={lastName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
required
|
||||
onChange={(e) => {
|
||||
setEmail(e.target.value);
|
||||
}}
|
||||
value={email}
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">Password</Label>
|
||||
<Input
|
||||
id="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
autoComplete="new-password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="password">Confirm Password</Label>
|
||||
<Input
|
||||
id="password_confirmation"
|
||||
value={passwordConfirmation}
|
||||
onChange={(e) => setPasswordConfirmation(e.target.value)}
|
||||
autoComplete="new-password"
|
||||
placeholder="Confirm Password"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="image">Profile Image (optional)</Label>
|
||||
<div className="flex items-end gap-4">
|
||||
{imagePreview && (
|
||||
<div className="relative w-16 h-16 rounded-sm overflow-hidden">
|
||||
<Image
|
||||
src={imagePreview}
|
||||
alt="Profile preview"
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-2 w-full">
|
||||
<Input
|
||||
id="image"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleImageChange}
|
||||
className="w-full"
|
||||
/>
|
||||
{imagePreview && (
|
||||
<X
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
setImage(null);
|
||||
setImagePreview(null);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="submit"
|
||||
className="w-full"
|
||||
disabled={loading}
|
||||
onClick={async () => {
|
||||
await signUp.email({
|
||||
email,
|
||||
password,
|
||||
name: \`\${firstName} \${lastName}\`,
|
||||
image: image ? await convertImageToBase64(image) : "",
|
||||
callbackURL: "/dashboard",
|
||||
fetchOptions: {
|
||||
onResponse: () => {
|
||||
setLoading(false);
|
||||
},
|
||||
onRequest: () => {
|
||||
setLoading(true);
|
||||
},
|
||||
onError: (ctx) => {
|
||||
toast.error(ctx.error.message);
|
||||
},
|
||||
onSuccess: async () => {
|
||||
router.push("/dashboard");
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<Loader2 size={16} className="animate-spin" />
|
||||
) : (
|
||||
"Create an account"
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="flex justify-center w-full border-t py-4">
|
||||
<p className="text-center text-xs text-neutral-500">
|
||||
Secured by <span className="text-orange-400">better-auth.</span>
|
||||
</p>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
async function convertImageToBase64(file: File): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}`;
|
||||
346
docs/components/builder/social-provider.tsx
Normal file
346
docs/components/builder/social-provider.tsx
Normal file
@@ -0,0 +1,346 @@
|
||||
import { SVGProps } from "react";
|
||||
|
||||
export const socialProviders = {
|
||||
apple: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M17.05 20.28c-.98.95-2.05.8-3.08.35c-1.09-.46-2.09-.48-3.24 0c-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8c1.18-.24 2.31-.93 3.57-.84c1.51.12 2.65.72 3.4 1.8c-3.12 1.87-2.38 5.98.48 7.13c-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25c.29 2.58-2.34 4.5-3.74 4.25"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
{...props}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M17.05 20.28c-.98.95-2.05.8-3.08.35c-1.09-.46-2.09-.48-3.24 0c-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8c1.18-.24 2.31-.93 3.57-.84c1.51.12 2.65.72 3.4 1.8c-3.12 1.87-2.38 5.98.48 7.13c-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25c.29 2.58-2.34 4.5-3.74 4.25"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
dropbox: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path d="m12.594 23.258l-.012.002l-.071.035l-.02.004l-.014-.004l-.071-.036q-.016-.004-.024.006l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.016-.018m.264-.113l-.014.002l-.184.093l-.01.01l-.003.011l.018.43l.005.012l.008.008l.201.092q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.003-.011l.018-.43l-.003-.012l-.01-.01z"></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m11.998 13.503l2.879 1.662c.426.246.923.34 1.365.34c.443 0 .94-.094 1.367-.34l.587-.34V17a1 1 0 0 1-.5.866l-5.196 3a1 1 0 0 1-1 0l-5.196-3a1 1 0 0 1-.5-.866v-2.172l.583.337c.426.246.923.34 1.366.34c.442 0 .939-.094 1.366-.34zM6.887 3.5c.434-.251 1.115-.274 1.594-.068l.138.068l3.379 1.95l3.379-1.95c.434-.251 1.115-.274 1.594-.068l.138.068l4.242 2.45c.447.257.476.664.09.942l-.09.057l-3.378 1.95l3.378 1.95c.447.258.476.665.09.943l-.09.057l-4.242 2.45c-.435.25-1.116.273-1.595.068l-.137-.068l-3.38-1.951l-3.378 1.95c-.435.252-1.116.274-1.595.07l-.137-.07l-4.243-2.449c-.447-.257-.476-.665-.09-.942l.09-.058L6.022 8.9L2.644 6.95c-.447-.257-.476-.665-.09-.942l.09-.058zm5.546 2.702c-.205-.119-.52-.136-.755-.051l-.111.05l-4.243 2.45c-.212.122-.236.313-.07.45l.07.05l4.243 2.449c.205.118.52.135.755.05l.111-.05l4.243-2.45c.212-.122.236-.312.07-.45l-.07-.05z"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g fill="none" fillRule="evenodd">
|
||||
<path d="m12.594 23.258l-.012.002l-.071.035l-.02.004l-.014-.004l-.071-.036q-.016-.004-.024.006l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.016-.018m.264-.113l-.014.002l-.184.093l-.01.01l-.003.011l.018.43l.005.012l.008.008l.201.092q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.003-.011l.018-.43l-.003-.012l-.01-.01z"></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m11.998 13.503l2.879 1.662c.426.246.923.34 1.365.34c.443 0 .94-.094 1.367-.34l.587-.34V17a1 1 0 0 1-.5.866l-5.196 3a1 1 0 0 1-1 0l-5.196-3a1 1 0 0 1-.5-.866v-2.172l.583.337c.426.246.923.34 1.366.34c.442 0 .939-.094 1.366-.34zM6.887 3.5c.434-.251 1.115-.274 1.594-.068l.138.068l3.379 1.95l3.379-1.95c.434-.251 1.115-.274 1.594-.068l.138.068l4.242 2.45c.447.257.476.664.09.942l-.09.057l-3.378 1.95l3.378 1.95c.447.258.476.665.09.943l-.09.057l-4.242 2.45c-.435.25-1.116.273-1.595.068l-.137-.068l-3.38-1.951l-3.378 1.95c-.435.252-1.116.274-1.595.07l-.137-.07l-4.243-2.449c-.447-.257-.476-.665-.09-.942l.09-.058L6.022 8.9L2.644 6.95c-.447-.257-.476-.665-.09-.942l.09-.058zm5.546 2.702c-.205-.119-.52-.136-.755-.051l-.111.05l-4.243 2.45c-.212.122-.236.313-.07.45l.07.05l4.243 2.449c.205.118.52.135.755.05l.111-.05l4.243-2.45c.212-.122.236-.312.07-.45l-.07-.05z"
|
||||
></path>
|
||||
</g>
|
||||
</svg>`,
|
||||
},
|
||||
discord: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.1.1 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.1 16.1 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02M8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12m6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.1.1 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.1 16.1 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02M8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12m6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
facebook: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M20 3H4a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h8.615v-6.96h-2.338v-2.725h2.338v-2c0-2.325 1.42-3.592 3.5-3.592c.699-.002 1.399.034 2.095.107v2.42h-1.435c-1.128 0-1.348.538-1.348 1.325v1.735h2.697l-.35 2.725h-2.348V21H20a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M20 3H4a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h8.615v-6.96h-2.338v-2.725h2.338v-2c0-2.325 1.42-3.592 3.5-3.592c.699-.002 1.399.034 2.095.107v2.42h-1.435c-1.128 0-1.348.538-1.348 1.325v1.735h2.697l-.35 2.725h-2.348V21H20a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
github: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33s1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33s1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
gitlab: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m22.749 9.769l-.031-.08l-3.027-7.9a.79.79 0 0 0-.782-.495a.8.8 0 0 0-.456.17a.8.8 0 0 0-.268.408L16.14 8.125H7.865L5.822 1.872a.8.8 0 0 0-.269-.409a.81.81 0 0 0-.926-.05c-.14.09-.25.22-.312.376L1.283 9.684l-.03.08a5.62 5.62 0 0 0 1.864 6.496l.01.008l.028.02l4.61 3.453l2.282 1.726l1.39 1.049a.935.935 0 0 0 1.13 0l1.389-1.05l2.281-1.726l4.639-3.473l.011-.01A5.62 5.62 0 0 0 22.75 9.77"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m22.749 9.769l-.031-.08l-3.027-7.9a.79.79 0 0 0-.782-.495a.8.8 0 0 0-.456.17a.8.8 0 0 0-.268.408L16.14 8.125H7.865L5.822 1.872a.8.8 0 0 0-.269-.409a.81.81 0 0 0-.926-.05c-.14.09-.25.22-.312.376L1.283 9.684l-.03.08a5.62 5.62 0 0 0 1.864 6.496l.01.008l.028.02l4.61 3.453l2.282 1.726l1.39 1.049a.935.935 0 0 0 1.13 0l1.389-1.05l2.281-1.726l4.639-3.473l.011-.01A5.62 5.62 0 0 0 22.75 9.77"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
google: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M11.99 13.9v-3.72h9.36c.14.63.25 1.22.25 2.05c0 5.71-3.83 9.77-9.6 9.77c-5.52 0-10-4.48-10-10S6.48 2 12 2c2.7 0 4.96.99 6.69 2.61l-2.84 2.76c-.72-.68-1.98-1.48-3.85-1.48c-3.31 0-6.01 2.75-6.01 6.12s2.7 6.12 6.01 6.12c3.83 0 5.24-2.65 5.5-4.22h-5.51z"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M11.99 13.9v-3.72h9.36c.14.63.25 1.22.25 2.05c0 5.71-3.83 9.77-9.6 9.77c-5.52 0-10-4.48-10-10S6.48 2 12 2c2.7 0 4.96.99 6.69 2.61l-2.84 2.76c-.72-.68-1.98-1.48-3.85-1.48c-3.31 0-6.01 2.75-6.01 6.12s2.7 6.12 6.01 6.12c3.83 0 5.24-2.65 5.5-4.22h-5.51z"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
linkedin: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93zM6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37z"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93zM6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37z"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
microsoft: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M2 3h9v9H2zm9 19H2v-9h9zM21 3v9h-9V3zm0 19h-9v-9h9z"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M2 3h9v9H2zm9 19H2v-9h9zM21 3v9h-9V3zm0 19h-9v-9h9z"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
twitch: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M11.64 5.93h1.43v4.28h-1.43m3.93-4.28H17v4.28h-1.43M7 2L3.43 5.57v12.86h4.28V22l3.58-3.57h2.85L20.57 12V2m-1.43 9.29l-2.85 2.85h-2.86l-2.5 2.5v-2.5H7.71V3.43h11.43Z"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M11.64 5.93h1.43v4.28h-1.43m3.93-4.28H17v4.28h-1.43M7 2L3.43 5.57v12.86h4.28V22l3.58-3.57h2.85L20.57 12V2m-1.43 9.29l-2.85 2.85h-2.86l-2.5 2.5v-2.5H7.71V3.43h11.43Z"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
spotify: {
|
||||
Icon: (props: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12.001 2c-5.5 0-10 4.5-10 10s4.5 10 10 10s10-4.5 10-10s-4.45-10-10-10m3.75 14.65c-2.35-1.45-5.3-1.75-8.8-.95c-.35.1-.65-.15-.75-.45c-.1-.35.15-.65.45-.75c3.8-.85 7.1-.5 9.7 1.1c.35.15.4.55.25.85c-.2.3-.55.4-.85.2m1-2.7c-2.7-1.65-6.8-2.15-9.95-1.15c-.4.1-.85-.1-.95-.5s.1-.85.5-.95c3.65-1.1 8.15-.55 11.25 1.35c.3.15.45.65.2 1s-.7.5-1.05.25M6.3 9.75c-.5.15-1-.15-1.15-.6c-.15-.5.15-1 .6-1.15c3.55-1.05 9.4-.85 13.1 1.35c.45.25.6.85.35 1.3c-.25.35-.85.5-1.3.25C14.7 9 9.35 8.8 6.3 9.75"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12.001 2c-5.5 0-10 4.5-10 10s4.5 10 10 10s10-4.5 10-10s-4.45-10-10-10m3.75 14.65c-2.35-1.45-5.3-1.75-8.8-.95c-.35.1-.65-.15-.75-.45c-.1-.35.15-.65.45-.75c3.8-.85 7.1-.5 9.7 1.1c.35.15.4.55.25.85c-.2.3-.55.4-.85.2m1-2.7c-2.7-1.65-6.8-2.15-9.95-1.15c-.4.1-.85-.1-.95-.5s.1-.85.5-.95c3.65-1.1 8.15-.55 11.25 1.35c.3.15.45.65.2 1s-.7.5-1.05.25M6.3 9.75c-.5.15-1-.15-1.15-.6c-.15-.5.15-1 .6-1.15c3.55-1.05 9.4-.85 13.1 1.35c.45.25.6.85.35 1.3c-.25.35-.85.5-1.3.25C14.7 9 9.35 8.8 6.3 9.75"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
x: {
|
||||
Icon: (props?: SVGProps<any>) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12.001 2c-5.5 0-10 4.5-10 10s4.5 10 10 10s10-4.5 10-10s-4.45-10-10-10m3.75 14.65c-2.35-1.45-5.3-1.75-8.8-.95c-.35.1-.65-.15-.75-.45c-.1-.35.15-.65.45-.75c3.8-.85 7.1-.5 9.7 1.1c.35.15.4.55.25.85c-.2.3-.55.4-.85.2m1-2.7c-2.7-1.65-6.8-2.15-9.95-1.15c-.4.1-.85-.1-.95-.5s.1-.85.5-.95c3.65-1.1 8.15-.55 11.25 1.35c.3.15.45.65.2 1s-.7.5-1.05.25M6.3 9.75c-.5.15-1-.15-1.15-.6c-.15-.5.15-1 .6-1.15c3.55-1.05 9.4-.85 13.1 1.35c.45.25.6.85.35 1.3c-.25.35-.85.5-1.3.25C14.7 9 9.35 8.8 6.3 9.75"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
stringIcon: `<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M12.001 2c-5.5 0-10 4.5-10 10s4.5 10 10 10s10-4.5 10-10s-4.45-10-10-10m3.75 14.65c-2.35-1.45-5.3-1.75-8.8-.95c-.35.1-.65-.15-.75-.45c-.1-.35.15-.65.45-.75c3.8-.85 7.1-.5 9.7 1.1c.35.15.4.55.25.85c-.2.3-.55.4-.85.2m1-2.7c-2.7-1.65-6.8-2.15-9.95-1.15c-.4.1-.85-.1-.95-.5s.1-.85.5-.95c3.65-1.1 8.15-.55 11.25 1.35c.3.15.45.65.2 1s-.7.5-1.05.25M6.3 9.75c-.5.15-1-.15-1.15-.6c-.15-.5.15-1 .6-1.15c3.55-1.05 9.4-.85 13.1 1.35c.45.25.6.85.35 1.3c-.25.35-.85.5-1.3.25C14.7 9 9.35 8.8 6.3 9.75"
|
||||
></path>
|
||||
</svg>`,
|
||||
},
|
||||
};
|
||||
12
docs/components/builder/store.ts
Normal file
12
docs/components/builder/store.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { atom } from "jotai";
|
||||
|
||||
export const optionsAtom = atom({
|
||||
email: true,
|
||||
passkey: false,
|
||||
socialProviders: ["google", "github"],
|
||||
magicLink: false,
|
||||
signUp: true,
|
||||
label: true,
|
||||
rememberMe: true,
|
||||
forgetPassword: true,
|
||||
});
|
||||
85
docs/components/builder/tabs.tsx
Normal file
85
docs/components/builder/tabs.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type Tab = {
|
||||
title: string;
|
||||
value: string;
|
||||
content?: string | React.ReactNode | any;
|
||||
};
|
||||
|
||||
export const AuthTabs = ({
|
||||
tabs: propTabs,
|
||||
}: {
|
||||
tabs: Tab[];
|
||||
}) => {
|
||||
const [active, setActive] = useState<Tab>(propTabs[0]);
|
||||
const [tabs, setTabs] = useState<Tab[]>(propTabs);
|
||||
const isActive = (tab: Tab) => {
|
||||
return tab.value === tabs[0].value;
|
||||
};
|
||||
const moveSelectedTabToTop = (idx: number) => {
|
||||
const newTabs = [...propTabs];
|
||||
const selectedTab = newTabs.splice(idx, 1);
|
||||
newTabs.unshift(selectedTab[0]);
|
||||
setTabs(newTabs);
|
||||
setActive(newTabs[0]);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-row items-center justify-start mt-0 relative no-visible-scrollbar border-x w-full border-t max-w-max bg-opacity-0",
|
||||
)}
|
||||
>
|
||||
{propTabs.map((tab, idx) => (
|
||||
<button
|
||||
key={tab.title}
|
||||
onClick={() => {
|
||||
moveSelectedTabToTop(idx);
|
||||
}}
|
||||
className={cn(
|
||||
"relative px-4 py-2 rounded-full opacity-80 hover:opacity-100",
|
||||
)}
|
||||
>
|
||||
{active.value === tab.value && (
|
||||
<div
|
||||
className={cn(
|
||||
"absolute inset-0 bg-gray-200 dark:bg-zinc-900/90 opacity-100",
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<span
|
||||
className={cn(
|
||||
"relative block text-black dark:text-white",
|
||||
active.value === tab.value
|
||||
? "text-opacity-100 font-medium"
|
||||
: "opacity-40 ",
|
||||
)}
|
||||
>
|
||||
{tab.title}
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="relative w-full h-full">
|
||||
{tabs.map((tab, idx) => (
|
||||
<div
|
||||
key={tab.value}
|
||||
style={{
|
||||
scale: 1 - idx * 0.1,
|
||||
zIndex: -idx,
|
||||
opacity: idx < 3 ? 1 - idx * 0.1 : 0,
|
||||
}}
|
||||
className={cn("w-50 h-full", isActive(tab) ? "" : "hidden")}
|
||||
>
|
||||
{tab.content}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -7,7 +7,7 @@ import clsx from "clsx";
|
||||
|
||||
import { GridPattern } from "./grid-pattern";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Check, Copy, Github, Icon } from "lucide-react";
|
||||
import { Check, Copy, Github, Icon, PlusIcon } from "lucide-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Highlight, themes } from "prism-react-renderer";
|
||||
import {
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
import { Icons } from "../icons";
|
||||
import { Cover } from "../ui/cover";
|
||||
import { PulicBetaBadge } from "../beta/badge";
|
||||
import { Builder } from "../builder";
|
||||
|
||||
const tabs: { name: "auth.ts" | "client.ts"; code: string }[] = [
|
||||
{
|
||||
@@ -63,7 +64,7 @@ export default function Hero() {
|
||||
<div className="relative z-10 md:text-center lg:text-left">
|
||||
<div className="relative">
|
||||
<div className="flex flex-col items-start gap-2">
|
||||
<PulicBetaBadge text="Beta" />
|
||||
<PulicBetaBadge text="v1 is out now!" />
|
||||
<div className="relative mt-2 flex items-center gap-2">
|
||||
<Cover>
|
||||
<p className="2xl relative inline tracking-tight opacity-90 md:text-3xl lg:text-5xl dark:text-white">
|
||||
@@ -78,7 +79,7 @@ export default function Hero() {
|
||||
</p>
|
||||
{
|
||||
<>
|
||||
<div className="mt-8 flex w-fit flex-col gap-4 font-sans md:flex-row md:justify-center lg:justify-start">
|
||||
<div className="mt-8 flex w-fit flex-col gap-4 font-sans md:flex-row md:justify-center lg:justify-start items-center">
|
||||
<Link
|
||||
href="/docs"
|
||||
className="hover:shadow-sm dark:border-stone-100 dark:hover:shadow-sm border-2 border-black bg-white px-4 py-1.5 text-sm uppercase text-black shadow-[1px_1px_rgba(0,0,0),2px_2px_rgba(0,0,0),3px_3px_rgba(0,0,0),4px_4px_rgba(0,0,0),5px_5px_0px_0px_rgba(0,0,0)] transition duration-200 md:px-8 dark:shadow-[1px_1px_rgba(255,255,255),2px_2px_rgba(255,255,255),3px_3px_rgba(255,255,255),4px_4px_rgba(255,255,255),5px_5px_0px_0px_rgba(255,255,255)]"
|
||||
@@ -86,19 +87,7 @@ export default function Hero() {
|
||||
Get Started
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="https://github.com/better-auth/better-auth"
|
||||
target="__blank"
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className="flex items-center gap-2 rounded-none"
|
||||
>
|
||||
<Github size={16} />
|
||||
View on GitHub
|
||||
</Button>
|
||||
</Link>
|
||||
<Builder />
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-none text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
@@ -13,7 +13,7 @@ const Checkbox = React.forwardRef<
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
"peer h-4 w-4 shrink-0 rounded-none border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"flex h-9 w-full rounded-none-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
|
||||
@@ -68,12 +68,15 @@
|
||||
"fumadocs-ui": "14.0.2",
|
||||
"geist": "^1.3.1",
|
||||
"input-otp": "^1.2.4",
|
||||
"jotai": "^2.10.3",
|
||||
"js-beautify": "^1.15.1",
|
||||
"lucide-react": "^0.435.0",
|
||||
"mini-svg-data-uri": "^1.4.4",
|
||||
"motion": "^10.18.0",
|
||||
"next": "^15.0.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"oslo": "^1.2.1",
|
||||
"prettier": "^3.3.3",
|
||||
"prism-react-renderer": "^2.4.0",
|
||||
"react": "^18.3.1",
|
||||
"react-codesandboxer": "^3.1.5",
|
||||
@@ -94,6 +97,7 @@
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-beautify": "^1.14.3",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "22.3.0",
|
||||
"@types/react": "^18.3.3",
|
||||
|
||||
@@ -151,6 +151,16 @@ export default {
|
||||
transform: "translate(calc(-50% - 0.5rem))",
|
||||
},
|
||||
},
|
||||
spotlight: {
|
||||
"0%": {
|
||||
opacity: 0,
|
||||
transform: "translate(-72%, -62%) scale(0.5)",
|
||||
},
|
||||
"100%": {
|
||||
opacity: 1,
|
||||
transform: "translate(-50%,-40%) scale(1)",
|
||||
},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
@@ -161,6 +171,7 @@ export default {
|
||||
"hrtl-scroll": "hrtl-scroll var(--anime-duration,10s) linear infinite",
|
||||
"hrtl-scroll-reverse":
|
||||
"hrtl-scroll-reverse var(--anime-duration,10s) linear infinite",
|
||||
spotlight: "spotlight 2s ease .75s 1 forwards",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
@@ -499,6 +499,12 @@ importers:
|
||||
input-otp:
|
||||
specifier: ^1.2.4
|
||||
version: 1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
jotai:
|
||||
specifier: ^2.10.3
|
||||
version: 2.10.3(@types/react@18.3.12)(react@18.3.1)
|
||||
js-beautify:
|
||||
specifier: ^1.15.1
|
||||
version: 1.15.1
|
||||
lucide-react:
|
||||
specifier: ^0.435.0
|
||||
version: 0.435.0(react@18.3.1)
|
||||
@@ -517,6 +523,9 @@ importers:
|
||||
oslo:
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
prettier:
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
prism-react-renderer:
|
||||
specifier: ^2.4.0
|
||||
version: 2.4.0(react@18.3.1)
|
||||
@@ -572,6 +581,9 @@ importers:
|
||||
specifier: ^3.23.8
|
||||
version: 3.23.8
|
||||
devDependencies:
|
||||
'@types/js-beautify':
|
||||
specifier: ^1.14.3
|
||||
version: 1.14.3
|
||||
'@types/mdx':
|
||||
specifier: ^2.0.13
|
||||
version: 2.0.13
|
||||
@@ -6856,6 +6868,9 @@ packages:
|
||||
'@types/jest@29.5.14':
|
||||
resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
|
||||
|
||||
'@types/js-beautify@1.14.3':
|
||||
resolution: {integrity: sha512-FMbQHz+qd9DoGvgLHxeqqVPaNRffpIu5ZjozwV8hf9JAGpIOzuAf4wGbRSo8LNITHqGjmmVjaMggTT5P4v4IHg==}
|
||||
|
||||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
@@ -11664,6 +11679,18 @@ packages:
|
||||
jose@5.9.6:
|
||||
resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==}
|
||||
|
||||
jotai@2.10.3:
|
||||
resolution: {integrity: sha512-Nnf4IwrLhNfuz2JOQLI0V/AgwcpxvVy8Ec8PidIIDeRi4KCFpwTFIpHAAcU+yCgnw/oASYElq9UY0YdUUegsSA==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
peerDependencies:
|
||||
'@types/react': '>=17.0.0'
|
||||
react: '>=17.0.0'
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
|
||||
joycon@3.1.1:
|
||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -23635,6 +23662,8 @@ snapshots:
|
||||
expect: 29.7.0
|
||||
pretty-format: 29.7.0
|
||||
|
||||
'@types/js-beautify@1.14.3': {}
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/json5@0.0.29': {}
|
||||
@@ -30140,6 +30169,11 @@ snapshots:
|
||||
|
||||
jose@5.9.6: {}
|
||||
|
||||
jotai@2.10.3(@types/react@18.3.12)(react@18.3.1):
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.12
|
||||
react: 18.3.1
|
||||
|
||||
joycon@3.1.1: {}
|
||||
|
||||
js-base64@3.7.7: {}
|
||||
|
||||
Reference in New Issue
Block a user