feat: Rework the loading.tsx on PRODUCT pages (#2666)

Co-authored-by: Matti Nannt <mail@matthiasnannt.com>
This commit is contained in:
kiran alex ch
2024-05-29 00:57:18 +05:30
committed by GitHub
parent 0d36e11bf4
commit b50bda8488
4 changed files with 444 additions and 158 deletions

View File

@@ -1,25 +1,34 @@
const LoadingCard = ({ title, description }) => {
"use client";
import { BrushIcon, KeyIcon, LanguagesIcon, ListChecksIcon, TagIcon, UsersIcon } from "lucide-react";
import { usePathname } from "next/navigation";
import { cn } from "@formbricks/lib/cn";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
const LoadingCard = () => {
return (
<div className="my-4 rounded-lg border border-slate-200">
<div className="grid content-center rounded-lg bg-slate-100 px-6 py-5 text-left text-slate-900">
<h3 className="text-lg font-medium leading-6">{title}</h3>
<p className="mt-1 text-sm text-slate-500">{description}</p>
<div className="w-full max-w-4xl rounded-xl border border-slate-200 bg-white py-4 shadow-sm">
<div className="grid content-center border-b border-slate-200 px-4 pb-4 text-left text-slate-900">
<h3 className="h-6 w-full max-w-56 animate-pulse rounded-lg bg-gray-100 text-lg font-medium leading-6"></h3>
<p className="mt-3 h-4 w-full max-w-80 animate-pulse rounded-lg bg-gray-100 text-sm text-slate-500 "></p>
</div>
<div className="w-full">
<div className="rounded-lg px-6 py-5 hover:bg-slate-100">
<div className="flex justify-end">
<div className="mt-4 h-6 w-28 animate-pulse rounded-full bg-slate-200"></div>
</div>
<div className="mt-6 rounded-lg border border-slate-200">
<div className="grid h-12 grid-cols-9 content-center rounded-t-lg bg-slate-100 px-6 text-left text-sm font-semibold text-slate-900">
<div className="col-span-2">Label</div>
<div className="col-span-2">API Key</div>
<div className="col-span-2">Last used</div>
<div className="col-span-2">Created at</div>
<div className="rounded-lg px-4 pt-4 ">
<div className="rounded-lg border border-slate-200">
<div className="grid h-12 grid-cols-10 content-center rounded-t-lg bg-slate-100 px-6 text-left text-sm font-semibold text-slate-900">
<div className="col-span-4 sm:col-span-2">Label</div>
<div className="col-span-4 hidden sm:col-span-5 sm:block">API Key</div>
<div className="col-span-4 sm:col-span-2">Created at</div>
</div>
<div className="px-6">
<div className="my-4 h-6 w-full animate-pulse rounded-full bg-slate-200"></div>
<div className="my-4 h-6 w-full animate-pulse rounded-full bg-slate-200"></div>
<div className="my-4 h-5 w-full animate-pulse rounded-full bg-slate-200"></div>
</div>
</div>
<div className="flex justify-start">
<div className="mt-4 flex h-7 w-44 animate-pulse flex-col items-center justify-center rounded-md bg-black text-sm text-white">
Loading
</div>
</div>
</div>
@@ -29,23 +38,76 @@ const LoadingCard = ({ title, description }) => {
};
const Loading = () => {
const cards = [
const pathname = usePathname();
let navigation = [
{
title: "Development Env Keys",
description: "Add and remove API keys for your Development environment.",
id: "general",
label: "General",
icon: <UsersIcon className="h-5 w-5" />,
current: pathname?.includes("/general"),
},
{
title: "Production Env Keys",
description: "Add and remove API keys for your Production environment.",
id: "look",
label: "Look & Feel",
icon: <BrushIcon className="h-5 w-5" />,
current: pathname?.includes("/look"),
},
{
id: "languages",
label: "Survey Languages",
icon: <LanguagesIcon className="h-5 w-5" />,
hidden: true,
current: pathname?.includes("/languages"),
},
{
id: "tags",
label: "Tags",
icon: <TagIcon className="h-5 w-5" />,
current: pathname?.includes("/tags"),
},
{
id: "api-keys",
label: "API Keys",
icon: <KeyIcon className="h-5 w-5" />,
current: pathname?.includes("/api-keys"),
},
{
id: "setup",
label: "Setup Guide",
icon: <ListChecksIcon className="h-5 w-5" />,
current: pathname?.includes("/setup"),
},
];
return (
<div>
<h2 className="my-4 text-2xl font-medium leading-6 text-slate-800">API Keys</h2>
{cards.map((card, index) => (
<LoadingCard key={index} {...card} />
))}
<PageContentWrapper>
<PageHeader pageTitle="Configuration">
<div className="grid h-10 w-full grid-cols-[auto,1fr] ">
<nav className="flex h-full min-w-full items-center space-x-4" aria-label="Tabs">
{navigation.map((navElem) => (
<div
key={navElem.id}
className={cn(
navElem.id === "api-keys"
? "border-brand-dark border-b-2 font-semibold text-slate-900"
: "border-transparent text-slate-500 transition-all duration-150 ease-in-out hover:border-slate-300 hover:text-slate-700",
"flex h-full items-center border-b-2 px-3 text-sm font-medium",
navElem.hidden && "hidden"
)}
aria-current={navElem.id === "api-keys" ? "page" : undefined}>
{navElem.label}
</div>
))}
</nav>
<div className="justify-self-end"></div>
</div>
</PageHeader>
<div className="mt-4 flex max-w-4xl animate-pulse items-center space-y-4 rounded-lg border bg-blue-50 p-6 text-sm text-blue-900 shadow-sm md:space-y-0 md:text-base"></div>
<LoadingCard />
</PageContentWrapper>
</div>
);
};

View File

@@ -1,12 +1,21 @@
"use client";
import { BrushIcon, KeyIcon, LanguagesIcon, ListChecksIcon, TagIcon, UsersIcon } from "lucide-react";
import { usePathname } from "next/navigation";
import { cn } from "@formbricks/lib/cn";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
const LoadingCard = ({ title, description, skeletonLines }) => {
return (
<div className="my-4 rounded-lg border border-slate-200">
<div className="grid content-center rounded-lg bg-slate-100 px-6 py-5 text-left text-slate-900">
<div className="w-full max-w-4xl rounded-xl border border-slate-200 bg-white py-4 shadow-sm">
<div className="grid content-center border-b border-slate-200 px-4 pb-4 text-left text-slate-900">
<h3 className="text-lg font-medium leading-6">{title}</h3>
<p className="mt-1 text-sm text-slate-500">{description}</p>
</div>
<div className="w-full">
<div className="rounded-lg px-6 py-5 hover:bg-slate-100">
<div className="rounded-lg px-4 py-4 pb-0 pt-2 ">
{skeletonLines.map((line, index) => (
<div key={index} className="mt-4">
<div className={`animate-pulse rounded-full bg-slate-200 ${line.classes}`}></div>
@@ -19,6 +28,8 @@ const LoadingCard = ({ title, description, skeletonLines }) => {
};
const Loading = () => {
const pathname = usePathname();
const cards = [
{
title: "Product Name",
@@ -38,12 +49,74 @@ const Loading = () => {
},
];
let navigation = [
{
id: "general",
label: "General",
icon: <UsersIcon className="h-5 w-5" />,
current: pathname?.includes("/general"),
},
{
id: "look",
label: "Look & Feel",
icon: <BrushIcon className="h-5 w-5" />,
current: pathname?.includes("/look"),
},
{
id: "languages",
label: "Survey Languages",
icon: <LanguagesIcon className="h-5 w-5" />,
hidden: true,
current: pathname?.includes("/languages"),
},
{
id: "tags",
label: "Tags",
icon: <TagIcon className="h-5 w-5" />,
current: pathname?.includes("/tags"),
},
{
id: "api-keys",
label: "API Keys",
icon: <KeyIcon className="h-5 w-5" />,
current: pathname?.includes("/api-keys"),
},
{
id: "setup",
label: "Setup Guide",
icon: <ListChecksIcon className="h-5 w-5" />,
current: pathname?.includes("/setup"),
},
];
return (
<div>
<h2 className="my-4 text-2xl font-medium leading-6 text-slate-800">Product Settings</h2>
{cards.map((card, index) => (
<LoadingCard key={index} {...card} />
))}
<PageContentWrapper>
<PageHeader pageTitle="Configuration">
<div className="grid h-10 w-full grid-cols-[auto,1fr] ">
<nav className="flex h-full min-w-full items-center space-x-4" aria-label="Tabs">
{navigation.map((navElem) => (
<div
key={navElem.id}
className={cn(
navElem.id === "general"
? "border-brand-dark border-b-2 font-semibold text-slate-900"
: "border-transparent text-slate-500 transition-all duration-150 ease-in-out hover:border-slate-300 hover:text-slate-700",
"flex h-full items-center border-b-2 px-3 text-sm font-medium",
navElem.hidden && "hidden"
)}
aria-current={navElem.id === "general" ? "page" : undefined}>
{navElem.label}
</div>
))}
</nav>
<div className="justify-self-end"></div>
</div>
</PageHeader>
{cards.map((card, index) => (
<LoadingCard key={index} {...card} />
))}
</PageContentWrapper>
</div>
);
};

View File

@@ -1,9 +1,15 @@
"use client";
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
import { BrushIcon, KeyIcon, LanguagesIcon, ListChecksIcon, TagIcon, UsersIcon } from "lucide-react";
import { usePathname } from "next/navigation";
import { cn } from "@formbricks/lib/cn";
import { Badge } from "@formbricks/ui/Badge";
import { Button } from "@formbricks/ui/Button";
import { Label } from "@formbricks/ui/Label";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
import { RadioGroup, RadioGroupItem } from "@formbricks/ui/RadioGroup";
import { Switch } from "@formbricks/ui/Switch";
@@ -16,130 +22,195 @@ const placements = [
];
const Loading = () => {
const pathname = usePathname();
let navigation = [
{
id: "general",
label: "General",
icon: <UsersIcon className="h-5 w-5" />,
current: pathname?.includes("/general"),
},
{
id: "look",
label: "Look & Feel",
icon: <BrushIcon className="h-5 w-5" />,
current: pathname?.includes("/look"),
},
{
id: "languages",
label: "Survey Languages",
icon: <LanguagesIcon className="h-5 w-5" />,
hidden: true,
current: pathname?.includes("/languages"),
},
{
id: "tags",
label: "Tags",
icon: <TagIcon className="h-5 w-5" />,
current: pathname?.includes("/tags"),
},
{
id: "api-keys",
label: "API Keys",
icon: <KeyIcon className="h-5 w-5" />,
current: pathname?.includes("/api-keys"),
},
{
id: "setup",
label: "Setup Guide",
icon: <ListChecksIcon className="h-5 w-5" />,
current: pathname?.includes("/setup"),
},
];
return (
<div>
<SettingsCard
title="Theme"
className="max-w-7xl"
description="Create a style theme for all surveys. You can enable custom styling for each survey.">
<div className="flex animate-pulse">
<div className="w-1/2">
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-4 rounded-lg bg-slate-50 p-4">
<div className="flex items-center gap-6">
<Switch />
<div className="flex flex-col">
<h3 className="text-sm font-semibold text-slate-700">Enable custom styling</h3>
<p className="text-xs text-slate-500">
Allow users to override this theme in the editor.
</p>
</div>
</div>
</div>
<div className="flex flex-col gap-4 bg-slate-50 p-4">
<div className="w-full rounded-lg border border-slate-300 bg-white">
<div className="flex flex-col p-4">
<h2 className="text-base font-semibold text-slate-700">Form Styling</h2>
<p className="mt-1 text-sm text-slate-500">
Style the question texts, descriptions and input fields.
</p>
</div>
</div>
<div className="w-full rounded-lg border border-slate-300 bg-white">
<div className="flex flex-col p-4">
<h2 className="text-base font-semibold text-slate-700">Card Styling</h2>
<p className="mt-1 text-sm text-slate-500">Style the survey card.</p>
</div>
</div>
<div className="w-full rounded-lg border border-slate-300 bg-white">
<div className="flex flex-col p-4">
<div className="flex items-center gap-2">
<h2 className="text-base font-semibold text-slate-700">Background Styling</h2>
<Badge text="Link Surveys" type="gray" size="normal" />
</div>
<p className="mt-1 text-sm text-slate-500">
Change the background to a color, image or animation.
</p>
</div>
</div>
</div>
</div>
</div>
<div className="w-1/2 bg-slate-100 px-6 pt-4">
<div className="relative flex h-[95] max-h-[95%] w-full items-center justify-center rounded-lg border border-slate-300 bg-slate-200">
<div className="flex h-full w-5/6 flex-1 flex-col">
<div className="flex h-8 w-full items-center rounded-t-lg bg-slate-100">
<div className="ml-6 flex space-x-2">
<div className="h-3 w-3 rounded-full bg-red-500"></div>
<div className="h-3 w-3 rounded-full bg-amber-500"></div>
<div className="h-3 w-3 rounded-full bg-emerald-500"></div>
</div>
<div className="ml-4 flex w-full justify-between font-mono text-sm text-slate-400">
<p>Preview</p>
<div className="flex items-center pr-6">Restart</div>
</div>
</div>
<div className="grid h-[500px] place-items-center bg-white">
<h1 className="text-xl font-semibold text-slate-700">Loading preview...</h1>
</div>
</div>
</div>
</div>
</div>
</SettingsCard>
<SettingsCard
title="In-app Survey Placement"
description="Change where surveys will be shown in your web app.">
<div className="w-full items-center">
<div className="flex cursor-not-allowed select-none">
<RadioGroup>
{placements.map((placement) => (
<div key={placement.value} className="flex items-center space-x-2 whitespace-nowrap ">
<RadioGroupItem
className="cursor-not-allowed select-none"
id={placement.value}
value={placement.value}
disabled={placement.disabled}
/>
<Label
htmlFor={placement.value}
className={cn(
placement.disabled ? "cursor-not-allowed text-slate-500" : "text-slate-900"
)}>
{placement.name}
</Label>
<PageContentWrapper>
<PageHeader pageTitle="Configuration">
<div className="grid h-10 w-full grid-cols-[auto,1fr] ">
<nav className="flex h-full min-w-full items-center space-x-4" aria-label="Tabs">
{navigation.map((navElem) => (
<div
key={navElem.id}
className={cn(
navElem.id === "look"
? "border-brand-dark border-b-2 font-semibold text-slate-900"
: "border-transparent text-slate-500 transition-all duration-150 ease-in-out hover:border-slate-300 hover:text-slate-700",
"flex h-full items-center border-b-2 px-3 text-sm font-medium",
navElem.hidden && "hidden"
)}
aria-current={navElem.id === "look" ? "page" : undefined}>
{navElem.label}
</div>
))}
</RadioGroup>
<div className="relative ml-8 h-40 w-full rounded bg-slate-200">
<div className={cn("absolute bottom-3 h-16 w-16 rounded bg-slate-700 sm:right-3")}></div>
</nav>
<div className="justify-self-end"></div>
</div>
</PageHeader>
<SettingsCard
title="Theme"
className="max-w-7xl"
description="Create a style theme for all surveys. You can enable custom styling for each survey.">
<div className="flex animate-pulse">
<div className="w-1/2">
<div className="flex flex-col gap-4 pr-6">
<div className="flex flex-col gap-4 rounded-lg bg-slate-50 p-4">
<div className="flex items-center gap-6">
<Switch />
<div className="flex flex-col">
<h3 className="text-sm font-semibold text-slate-700">Enable custom styling</h3>
<p className="text-xs text-slate-500">
Allow users to override this theme in the editor.
</p>
</div>
</div>
</div>
<div className="flex flex-col gap-3 bg-slate-50 p-4">
<div className="w-full rounded-lg border border-slate-300 bg-white">
<div className="flex flex-col p-4">
<h2 className="text-sm font-semibold text-slate-700">Form Styling</h2>
<p className="mt-1 text-xs text-slate-500">
Style the question texts, descriptions and input fields.
</p>
</div>
</div>
<div className="w-full rounded-lg border border-slate-300 bg-white">
<div className="flex flex-col p-4">
<h2 className="text-sm font-semibold text-slate-700">Card Styling</h2>
<p className="mt-1 text-xs text-slate-500">Style the survey card.</p>
</div>
</div>
<div className="w-full rounded-lg border border-slate-300 bg-white">
<div className="flex flex-col p-4">
<div className="flex items-center gap-2">
<h2 className="text-sm font-semibold text-slate-700">Background Styling</h2>
<Badge text="Link Surveys" type="gray" size="normal" />
</div>
<p className="mt-1 text-xs text-slate-500">
Change the background to a color, image or animation.
</p>
</div>
</div>
</div>
</div>
</div>
<div className="relative flex w-1/2 flex-row items-center justify-center rounded-lg bg-slate-100 pt-4">
<div className="relative mb-3 flex h-fit w-5/6 items-center justify-center rounded-lg border border-slate-300 bg-slate-200">
<div className="flex h-[95] max-h-[90%] w-4/6 flex-1 flex-col">
<div className="flex h-8 w-full items-center rounded-t-lg bg-slate-100">
<div className="ml-6 flex space-x-2">
<div className="h-3 w-3 rounded-full bg-red-500"></div>
<div className="h-3 w-3 rounded-full bg-amber-500"></div>
<div className="h-3 w-3 rounded-full bg-emerald-500"></div>
</div>
<div className="ml-4 flex w-full justify-between font-mono text-sm text-slate-400">
<p>Preview</p>
<div className="flex items-center pr-6">Restart</div>
</div>
</div>
<div className="grid h-[500px] place-items-center bg-white">
<h1 className="text-xl font-semibold text-slate-700">Loading preview...</h1>
</div>
</div>
</div>
</div>
</div>
<Button
variant="darkCTA"
className="pointer-events-none mt-4 animate-pulse cursor-not-allowed select-none bg-slate-200">
Loading
</Button>
</div>
</SettingsCard>
</SettingsCard>
<SettingsCard
title="Formbricks Signature"
description="We love your support but understand if you toggle it off.">
<div className="w-full items-center">
<div className="pointer-events-none flex cursor-not-allowed select-none items-center space-x-2">
<Switch id="signature" checked={false} />
<Label htmlFor="signature">Show &apos;Powered by Formbricks&apos; Signature</Label>
<SettingsCard
title="In-app Survey Placement"
description="Change where surveys will be shown in your web app.">
<div className="w-full items-center">
<div className="flex cursor-not-allowed select-none">
<RadioGroup>
{placements.map((placement) => (
<div key={placement.value} className="flex items-center space-x-2 whitespace-nowrap ">
<RadioGroupItem
className="cursor-not-allowed select-none"
id={placement.value}
value={placement.value}
disabled={placement.disabled}
/>
<Label
htmlFor={placement.value}
className={cn(
placement.disabled ? "cursor-not-allowed text-slate-500" : "text-slate-900"
)}>
{placement.name}
</Label>
</div>
))}
</RadioGroup>
<div className="relative ml-8 h-40 w-full rounded bg-slate-200">
<div className={cn("absolute bottom-3 h-16 w-16 rounded bg-slate-700 sm:right-3")}></div>
</div>
</div>
<Button
variant="darkCTA"
className="pointer-events-none mt-4 animate-pulse cursor-not-allowed select-none bg-slate-200">
Loading
</Button>
</div>
</div>
</SettingsCard>
</SettingsCard>
<SettingsCard
title="Formbricks Signature"
description="We love your support but understand if you toggle it off.">
<div className="w-full items-center">
<div className="pointer-events-none flex cursor-not-allowed select-none items-center space-x-2">
<Switch id="signature" checked={false} />
<Label htmlFor="signature">Show &apos;Powered by Formbricks&apos; Signature</Label>
</div>
</div>
</SettingsCard>
</PageContentWrapper>
</div>
);
};

View File

@@ -1,15 +1,25 @@
"use client";
import { BrushIcon, KeyIcon, LanguagesIcon, ListChecksIcon, TagIcon, UsersIcon } from "lucide-react";
import { usePathname } from "next/navigation";
import { cn } from "@formbricks/lib/cn";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
const LoadingCard = ({ title, description, skeletonLines }) => {
return (
<div className="my-4 rounded-lg border border-slate-200">
<div className="grid content-center rounded-lg bg-slate-100 px-6 py-5 text-left text-slate-900">
<div className="w-full max-w-4xl rounded-xl border border-slate-200 bg-white py-4 text-left shadow-sm">
<div className="grid content-center border-b border-slate-200 px-4 pb-4 text-left text-slate-900">
<h3 className="text-lg font-medium leading-6">{title}</h3>
<p className="mt-1 text-sm text-slate-500">{description}</p>
</div>
<div className="w-full">
<div className="rounded-lg px-6 py-5 hover:bg-slate-100">
<div className="rounded-lg px-4 ">
{skeletonLines.map((line, index) => (
<div key={index} className="mt-4">
<div className={`animate-pulse bg-slate-200 ${line.classes}`}></div>
<div
className={`flex animate-pulse flex-col items-center justify-center space-y-2 rounded-lg bg-slate-200 py-6 text-center ${line.classes}`}></div>
</div>
))}
</div>
@@ -19,11 +29,18 @@ const LoadingCard = ({ title, description, skeletonLines }) => {
};
const Loading = () => {
const pathname = usePathname();
const cards = [
{
title: "Widget Status",
description: "Check if the Formbricks widget is alive and kicking.",
skeletonLines: [{ classes: "h-32 max-w-full rounded-md" }],
skeletonLines: [{ classes: " h-44 max-w-full rounded-md" }],
},
{
title: "Your EnvironmentId",
description: "This Id uniquely identifies this Formbricks environment.",
skeletonLines: [{ classes: "h-6 w-4/6 rounded-full" }],
},
{
title: "How to setup",
@@ -39,12 +56,75 @@ const Loading = () => {
},
];
let navigation = [
{
id: "general",
label: "General",
icon: <UsersIcon className="h-5 w-5" />,
current: pathname?.includes("/general"),
},
{
id: "look",
label: "Look & Feel",
icon: <BrushIcon className="h-5 w-5" />,
current: pathname?.includes("/look"),
},
{
id: "languages",
label: "Survey Languages",
icon: <LanguagesIcon className="h-5 w-5" />,
hidden: true,
current: pathname?.includes("/languages"),
},
{
id: "tags",
label: "Tags",
icon: <TagIcon className="h-5 w-5" />,
current: pathname?.includes("/tags"),
},
{
id: "api-keys",
label: "API Keys",
icon: <KeyIcon className="h-5 w-5" />,
current: pathname?.includes("/api-keys"),
},
{
id: "setup",
label: "Setup Guide",
icon: <ListChecksIcon className="h-5 w-5" />,
current: pathname?.includes("/setup"),
},
];
return (
<div>
<h2 className="my-4 text-2xl font-medium leading-6 text-slate-800">Setup Checklist</h2>
{cards.map((card, index) => (
<LoadingCard key={index} {...card} />
))}
<PageContentWrapper>
<PageHeader pageTitle="Configuration">
<div className="grid h-10 w-full grid-cols-[auto,1fr] ">
<nav className="flex h-full min-w-full items-center space-x-4" aria-label="Tabs">
{navigation.map((navElem) => (
<div
key={navElem.id}
className={cn(
navElem.id === "setup"
? "border-brand-dark border-b-2 font-semibold text-slate-900"
: "border-transparent text-slate-500 transition-all duration-150 ease-in-out hover:border-slate-300 hover:text-slate-700",
"flex h-full items-center border-b-2 px-3 text-sm font-medium",
navElem.hidden && "hidden"
)}
aria-current={navElem.id === "setup" ? "page" : undefined}>
{navElem.label}
</div>
))}
</nav>
<div className="justify-self-end"></div>
</div>
</PageHeader>
<div className="mt-4 flex max-w-4xl animate-pulse items-center space-y-4 rounded-lg border bg-blue-50 p-6 text-sm text-blue-900 shadow-sm md:space-y-0 md:text-base"></div>
{cards.map((card, index) => (
<LoadingCard key={index} {...card} />
))}
</PageContentWrapper>
</div>
);
};