Skip to content

Commit

Permalink
Add live demo
Browse files Browse the repository at this point in the history
arjunkomath committed Jan 19, 2025
1 parent 2504724 commit e35357a
Showing 5 changed files with 207 additions and 10 deletions.
28 changes: 26 additions & 2 deletions app/(auth)/sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { logtoConfig } from "@/app/logto";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { DotPattern } from "@/components/ui/dot-pattern";
import { cn } from "@/lib/utils";
import { signIn } from "@logto/next/server-actions";
import Image from "next/image";
import Link from "next/link";
import logo from "../../../public/images/logo.png";

export default function SignInForm() {
export default async function SignInForm(props: {
searchParams: Promise<{
demo: string;
}>;
}) {
const query = await props.searchParams;
const isDemo = query.demo === "true";

return (
<div className="m-6 flex h-full items-center justify-center">
<Card className="w-full max-w-md">
<DotPattern />
<Card className="w-full max-w-md z-10">
<div className="flex p-6 lg:flex-1">
<Image
src={logo}
@@ -34,6 +44,20 @@ export default function SignInForm() {
</CardHeader>

<CardContent className="grid gap-4">
{isDemo ? (
<div className="bg-gray-100 dark:bg-gray-800 p-4 rounded-md space-y-2">
<p className="text-sm text-gray-600 dark:text-gray-300">
Try the demo account to see how it works, login with the
following credentials.
</p>
<div className="text-sm text-gray-600 dark:text-gray-300">
User ID: <pre className="font-semibold">demo</pre>
</div>
<div className="text-sm text-gray-600 dark:text-gray-300">
Password: <pre className="font-semibold">w-okDQsz</pre>
</div>
</div>
) : null}
<Button
type="button"
onClick={async () => {
1 change: 0 additions & 1 deletion app/(dashboard)/[tenant]/today/page.tsx
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ import {
toDateTimeString,
toEndOfDay,
toStartOfDay,
toTimeZone,
} from "@/lib/utils/date";
import { database } from "@/lib/utils/useDatabase";
import { filterByRepeatRule } from "@/lib/utils/useEvents";
20 changes: 13 additions & 7 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { FeaturesSection } from "@/components/feature-section";
import { Footer } from "@/components/layout/footer";
import { Header } from "@/components/layout/header";
import { buttonVariants } from "@/components/ui/button";
import { SITE_METADATA } from "@/data/marketing";
import Link from "next/link";

@@ -8,7 +10,7 @@ export default async function Home() {
<div className="h-full">
<Header />

<div className="relative isolate px-6 pt-14 lg:px-8">
<div className="relative isolate px-6 pt-12 lg:px-8">
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
aria-hidden="true"
@@ -30,12 +32,14 @@ export default async function Home() {
{SITE_METADATA.DESCRIPTION}
</p>
<div className="mt-10 flex flex-col items-center justify-center gap-y-6 md:flex-row md:gap-x-6 md:gap-y-0">
{/* <Link
href="/start"
prefetch={false}
>
Get started
</Link> */}
<Link
target="_blank"
href="/sign-in?demo=true"
prefetch={false}
className={buttonVariants({ variant: "outline" })}
>
Live Demo
</Link>

<Link
href="https://github.com/techulus/manage"
@@ -78,6 +82,8 @@ export default async function Home() {
</div>
</div>

<FeaturesSection />

<Footer />
</div>
);
111 changes: 111 additions & 0 deletions components/feature-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { cn } from "@/lib/utils";
import {
Cloud,
CloudLightning,
DollarSign,
HeartIcon,
HelpCircle,
RouterIcon,
ShieldQuestion,
TerminalIcon,
} from "lucide-react";

export function FeaturesSection() {
const features = [
{
title: "Open-source",
description:
"Built for engineers, developers, dreamers, thinkers and doers.",
icon: <TerminalIcon />,
},
{
title: "Ease of use",
description:
"Easily manage your tasks, events, documents & more with a single click.",
icon: <ShieldQuestion />,
},
{
title: "File Sharing",
description:
"Upload and share files within your team to centralize project resources.",
icon: <Cloud />,
},
{
title: "Pricing like no other",
description:
"It's free to self-host, we might charge you for the cloud version.",
icon: <DollarSign />,
},
{
title: "Multi-tenant Architecture",
description:
"Efficiently manage users and teams with integrated authentication and authorization.",
icon: <RouterIcon />,
},
{
title: "Commenting System",
description:
"Facilitate discussions and feedback with a built-in commenting feature.",
icon: <HelpCircle />,
},
{
title: "Activity Logs",
description:
"Monitor project activities with comprehensive activity logs.",
icon: <CloudLightning />,
},
{
title: "And everything else",
description: "I just ran out of copy ideas. Accept my sincere apologies",
icon: <HeartIcon />,
},
];
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 relative z-10 py-4 max-w-7xl mx-auto">
{features.map((feature, index) => (
<Feature key={feature.title} {...feature} index={index} />
))}
</div>
);
}

const Feature = ({
title,
description,
icon,
index,
}: {
title: string;
description: string;
icon: React.ReactNode;
index: number;
}) => {
return (
<div
className={cn(
"flex flex-col lg:border-r py-10 relative group/feature dark:border-neutral-800",
(index === 0 || index === 4) && "lg:border-l dark:border-neutral-800",
index < 4 && "lg:border-b dark:border-neutral-800",
)}
>
{index < 4 && (
<div className="opacity-0 group-hover/feature:opacity-100 transition duration-200 absolute inset-0 h-full w-full bg-gradient-to-t from-neutral-100 dark:from-neutral-800 to-transparent pointer-events-none" />
)}
{index >= 4 && (
<div className="opacity-0 group-hover/feature:opacity-100 transition duration-200 absolute inset-0 h-full w-full bg-gradient-to-b from-neutral-100 dark:from-neutral-800 to-transparent pointer-events-none" />
)}
<div className="mb-4 relative z-10 px-10 text-neutral-600 dark:text-neutral-400">
{icon}
</div>
<div className="text-lg font-bold mb-2 relative z-10 px-10">
<div className="absolute left-0 inset-y-0 h-6 group-hover/feature:h-8 w-1 rounded-tr-full rounded-br-full bg-neutral-300 dark:bg-neutral-700 group-hover/feature:bg-primary transition-all duration-200 origin-center" />
<span className="group-hover/feature:translate-x-2 transition duration-200 inline-block text-neutral-800 dark:text-neutral-100">
{title}
</span>
</div>
<p className="text-sm text-neutral-600 dark:text-neutral-300 max-w-xs relative z-10 px-10">
{description}
</p>
</div>
);
};
57 changes: 57 additions & 0 deletions components/ui/dot-pattern.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useId } from "react";

import { cn } from "@/lib/utils";

interface DotPatternProps {
width?: any;
height?: any;
x?: any;
y?: any;
cx?: any;
cy?: any;
cr?: any;
className?: string;
[key: string]: any;
}

function DotPattern({
width = 16,
height = 16,
x = 0,
y = 0,
cx = 1,
cy = 1,
cr = 1,
className,
...props
}: DotPatternProps) {
const id = useId();

return (
<svg
aria-hidden="true"
className={cn(
"pointer-events-none absolute inset-0 h-full w-full fill-neutral-400/80",
className,
)}
{...props}
>
<defs>
<pattern
id={id}
width={width}
height={height}
patternUnits="userSpaceOnUse"
patternContentUnits="userSpaceOnUse"
x={x}
y={y}
>
<circle id="pattern-circle" cx={cx} cy={cy} r={cr} />
</pattern>
</defs>
<rect width="100%" height="100%" strokeWidth={0} fill={`url(#${id})`} />
</svg>
);
}

export { DotPattern };

0 comments on commit e35357a

Please sign in to comment.