From c1ae2ed9f351bb66da0d055d340ecae6c52533a2 Mon Sep 17 00:00:00 2001 From: Bereket Engida Date: Fri, 16 Jan 2026 12:23:55 -0800 Subject: [PATCH] refactor: simplify social provider handling and improve layout in Builder and SignIn components --- .../builder/code-tabs/code-editor.tsx | 14 +- docs/components/builder/code-tabs/theme.ts | 79 ---------- docs/components/builder/index.tsx | 139 ++++-------------- docs/components/builder/sign-in.tsx | 94 +++++++++--- docs/components/builder/social-provider.tsx | 14 +- 5 files changed, 116 insertions(+), 224 deletions(-) delete mode 100644 docs/components/builder/code-tabs/theme.ts diff --git a/docs/components/builder/code-tabs/code-editor.tsx b/docs/components/builder/code-tabs/code-editor.tsx index 18e426fb2c..c48d01e487 100644 --- a/docs/components/builder/code-tabs/code-editor.tsx +++ b/docs/components/builder/code-tabs/code-editor.tsx @@ -1,10 +1,10 @@ "use client"; import { Check, Copy } from "lucide-react"; -import { Highlight } from "prism-react-renderer"; +import { useTheme } from "next-themes"; +import { Highlight, themes } from "prism-react-renderer"; import { useState } from "react"; import { Button } from "@/components/ui/button"; -import theme from "./theme"; interface CodeEditorProps { code: string; @@ -13,6 +13,7 @@ interface CodeEditorProps { export function CodeEditor({ code, language }: CodeEditorProps) { const [isCopied, setIsCopied] = useState(false); + const { resolvedTheme } = useTheme(); const copyToClipboard = async () => { try { @@ -24,9 +25,11 @@ export function CodeEditor({ code, language }: CodeEditorProps) { } }; + const theme = resolvedTheme === "dark" ? themes.vsDark : themes.vsLight; + return (
-
+
{({ className, style, tokens, getLineProps, getTokenProps }) => (
@@ -42,7 +45,10 @@ export function CodeEditor({ code, language }: CodeEditorProps) { className={lineProps.className} style={lineProps.style} > - + {i + 1} {line.map((token, key) => { diff --git a/docs/components/builder/code-tabs/theme.ts b/docs/components/builder/code-tabs/theme.ts deleted file mode 100644 index 7919c02720..0000000000 --- a/docs/components/builder/code-tabs/theme.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { 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; diff --git a/docs/components/builder/index.tsx b/docs/components/builder/index.tsx index f78e44b62e..ab1f5b12c2 100644 --- a/docs/components/builder/index.tsx +++ b/docs/components/builder/index.tsx @@ -1,7 +1,7 @@ "use client"; import { useAtom } from "jotai"; -import { CircleX, ListFilter, Moon, PlusIcon, Sun, X } from "lucide-react"; +import { ArrowLeft, Moon, PlusIcon, Sun } from "lucide-react"; import { useTheme } from "next-themes"; import { useMemo, useState } from "react"; import { cn } from "@/lib/utils"; @@ -28,7 +28,6 @@ import { DialogTitle, DialogTrigger, } from "../ui/dialog"; -import { Input } from "../ui/input"; import { Label } from "../ui/label"; import { ScrollArea } from "../ui/scroll-area"; import { Switch } from "../ui/switch"; @@ -271,50 +270,6 @@ export function Builder() { const [options, setOptions] = useAtom(optionsAtom); const { setTheme, resolvedTheme } = useTheme(); - const [socialProviderSearchInput, setSocialProviderSearchInputState] = - useState(""); - const [debouncedSearch, setDebouncedSearch] = useState(""); - const [debounceTimer, setDebounceTimer] = useState(null); - - const setSocialProviderSearchInput = (value: string) => { - setSocialProviderSearchInputState(value); - - if (value === "") { - if (debounceTimer) { - clearTimeout(debounceTimer); - } - setDebouncedSearch(""); - setDebounceTimer(null); - return; - } - - if (debounceTimer) { - clearTimeout(debounceTimer); - } - - const id = window.setTimeout(() => { - setDebouncedSearch(value); - setDebounceTimer(null); - }, 300); - - setDebounceTimer(id); - }; - - const filteredSocialProviders = useMemo(() => { - const providers = Object.entries(socialProviders); - if (debouncedSearch.length === 0) { - return providers; - } - - return providers.filter(([name]) => - name.toLowerCase().includes(debouncedSearch.toLowerCase()), - ); - }, [debouncedSearch]); - - const resetSocialProviderSearch = () => { - setSocialProviderSearchInput(""); - }; - const reset = () => { setOptions(defaultOptions); setFramework("nextjs"); @@ -337,7 +292,7 @@ export function Builder() { } return optionValue !== defaultValue; }); - }, [debouncedSearch, options]); + }, [options]); return ( @@ -368,7 +323,7 @@ export function Builder() {
- )} -
+
- {filteredSocialProviders + {Object.entries(socialProviders) .sort(([a], [b]) => a.localeCompare(b)) .map(([provider, { Icon }]) => ( ))} - {filteredSocialProviders.length === 0 && ( -
- No providers found. - -
- )}
@@ -690,36 +609,32 @@ export function Builder() { - + Continue + )} {currentStep === 1 && ( <> - - Choose Framework -

+ + Choose Framework {frameworks.map((fm) => ( @@ -754,16 +669,18 @@ export function Builder() { {currentStep === 2 && ( <> - - Code -

+ + Code diff --git a/docs/components/builder/sign-in.tsx b/docs/components/builder/sign-in.tsx index 520fd35fe4..5d9ab36f22 100644 --- a/docs/components/builder/sign-in.tsx +++ b/docs/components/builder/sign-in.tsx @@ -100,38 +100,86 @@ export default function SignIn() { Sign-in with Passkey )} -

3 - ? "flex-row flex-wrap" - : "flex-col", - )} - > - {Object.keys(socialProviders).map((provider) => { - if (options.socialProviders.includes(provider)) { +
+ {(() => { + const selectedProviders = options.socialProviders; + const count = selectedProviders.length; + + // Layout rules: + // - 1-3 providers: full width, show "Sign in with [Provider]" + // - 4+ providers: wrap in rows with provider names (top) and icons (bottom) + // - namedCount = count % 4 (or 4 if evenly divisible) + // - named providers show just the provider name, 2 per row (1/2 width each) + // - icon-only providers show just icon, 4 per row (1/4 width each) + + if (count <= 3) { + // 1-3 providers: full width with "Sign in with [Provider]" + return selectedProviders.map((provider) => { + const { Icon } = + socialProviders[provider as keyof typeof socialProviders]; + const providerName = + provider.charAt(0).toUpperCase() + provider.slice(1); + + return ( + + ); + }); + } + + // 4+ providers: use wrapping layout + const remainder = count % 4; + const namedCount = remainder === 0 ? 4 : remainder; + + return selectedProviders.map((provider, index) => { const { Icon } = socialProviders[provider as keyof typeof socialProviders]; + const isNamed = index < namedCount; + const providerName = + provider.charAt(0).toUpperCase() + provider.slice(1); + + // Determine width class and if full width (for text display) + let widthClass: string; + let isFullWidth = false; + if (isNamed) { + // Named providers: 2 per row (1/2 width each) + // If odd number of named providers, first one takes full width + if (namedCount === 1) { + widthClass = "w-full"; + isFullWidth = true; + } else if (namedCount % 2 === 1 && index === 0) { + // Odd number of named providers, first one takes full width + widthClass = "w-full"; + isFullWidth = true; + } else { + widthClass = "w-[calc(50%-0.25rem)]"; + } + } else { + // Icon-only providers: 1/4 width (4 per row) + widthClass = "w-[calc(25%-0.375rem)]"; + } + return ( ); - } - return null; - })} + }); + })()}
diff --git a/docs/components/builder/social-provider.tsx b/docs/components/builder/social-provider.tsx index fa1d69e7ad..4e1f39f377 100644 --- a/docs/components/builder/social-provider.tsx +++ b/docs/components/builder/social-provider.tsx @@ -4,28 +4,28 @@ export const socialProviders = { apple: { Icon: (props?: SVGProps) => ( + d="M462.595 399.003c-7.743 17.888-16.908 34.353-27.527 49.492c-14.474 20.637-26.326 34.923-35.459 42.855c-14.159 13.021-29.329 19.69-45.573 20.068c-11.662 0-25.726-3.318-42.096-10.05c-16.425-6.7-31.519-10.019-45.32-10.019c-14.475 0-29.999 3.318-46.603 10.019c-16.63 6.731-30.027 10.24-40.27 10.587c-15.578.664-31.105-6.195-46.603-20.606c-9.892-8.628-22.265-23.418-37.088-44.372c-15.903-22.375-28.977-48.322-39.221-77.904c-10.969-31.952-16.469-62.892-16.469-92.846c0-34.313 7.414-63.906 22.265-88.706c11.672-19.92 27.199-35.633 46.631-47.169s40.431-17.414 63.043-17.79c12.373 0 28.599 3.827 48.762 11.349c20.107 7.547 33.017 11.375 38.677 11.375c4.232 0 18.574-4.475 42.887-13.397c22.992-8.274 42.397-11.7 58.293-10.35c43.076 3.477 75.438 20.457 96.961 51.05c-38.525 23.343-57.582 56.037-57.203 97.979c.348 32.669 12.199 59.855 35.491 81.44c10.555 10.019 22.344 17.762 35.459 23.26c-2.844 8.248-5.846 16.149-9.038 23.735zM363.801 10.242c0 25.606-9.355 49.514-28.001 71.643c-22.502 26.307-49.719 41.508-79.234 39.11a80 80 0 0 1-.594-9.703c0-24.582 10.701-50.889 29.704-72.398c9.488-10.89 21.554-19.946 36.187-27.17C336.464 4.608 350.275.672 363.264-.001c.379 3.423.538 6.846.538 10.242z" + /> ), stringIcon: ` + d="M462.595 399.003c-7.743 17.888-16.908 34.353-27.527 49.492c-14.474 20.637-26.326 34.923-35.459 42.855c-14.159 13.021-29.329 19.69-45.573 20.068c-11.662 0-25.726-3.318-42.096-10.05c-16.425-6.7-31.519-10.019-45.32-10.019c-14.475 0-29.999 3.318-46.603 10.019c-16.63 6.731-30.027 10.24-40.27 10.587c-15.578.664-31.105-6.195-46.603-20.606c-9.892-8.628-22.265-23.418-37.088-44.372c-15.903-22.375-28.977-48.322-39.221-77.904c-10.969-31.952-16.469-62.892-16.469-92.846c0-34.313 7.414-63.906 22.265-88.706c11.672-19.92 27.199-35.633 46.631-47.169s40.431-17.414 63.043-17.79c12.373 0 28.599 3.827 48.762 11.349c20.107 7.547 33.017 11.375 38.677 11.375c4.232 0 18.574-4.475 42.887-13.397c22.992-8.274 42.397-11.7 58.293-10.35c43.076 3.477 75.438 20.457 96.961 51.05c-38.525 23.343-57.582 56.037-57.203 97.979c.348 32.669 12.199 59.855 35.491 81.44c10.555 10.019 22.344 17.762 35.459 23.26c-2.844 8.248-5.846 16.149-9.038 23.735zM363.801 10.242c0 25.606-9.355 49.514-28.001 71.643c-22.502 26.307-49.719 41.508-79.234 39.11a80 80 0 0 1-.594-9.703c0-24.582 10.701-50.889 29.704-72.398c9.488-10.89 21.554-19.946 36.187-27.17C336.464 4.608 350.275.672 363.264-.001c.379 3.423.538 6.846.538 10.242z" + /> `, }, dropbox: {