Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/dashboard/src/components/layouts/dashboard-topbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,14 @@ export function DashboardTopbar({ user }: DashboardTopbarProps) {
variant="ghost"
size="sm"
asChild
iconLeft={<item.icon size={15} strokeWidth={2} />}
className="text-muted-foreground [&.active]:bg-surface-1 [&.active]:text-foreground"
>
<Link
to={item.to as string}
activeOptions={{ exact: true }}
activeProps={{ className: "active" }}
>
<item.icon size={15} strokeWidth={2} />
<span>{item.label}</span>
</Link>
</Button>
Expand All @@ -146,10 +146,10 @@ export function DashboardTopbar({ user }: DashboardTopbarProps) {
<Button
variant="ghost"
size="icon"
iconLeft={<MoreHorizontalIcon className="size-5" strokeWidth={2} />}
className="size-8 text-muted-foreground hover:bg-surface-1"
>
<MoreHorizontalIcon className="size-5" strokeWidth={2} />
</Button>
aria-label="More actions"
/>
</div>
</nav>
);
Expand Down
97 changes: 61 additions & 36 deletions apps/dashboard/src/routes/login.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { GitHubLogo } from "@quickhub/icons";
import { Button } from "@quickhub/ui/components/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@quickhub/ui/components/card";
import { Logo } from "@quickhub/ui/components/logo";
import { createFileRoute, redirect } from "@tanstack/react-router";
import { signIn } from "#/lib/auth.client";
Expand All @@ -21,37 +15,68 @@ export const Route = createFileRoute("/login")({

function LoginPage() {
return (
<main className="flex min-h-dvh items-center justify-center bg-[radial-gradient(circle_at_top,_color-mix(in_oklch,_var(--color-primary)_6%,_transparent),_transparent_48%),linear-gradient(180deg,_color-mix(in_oklch,_var(--color-secondary)_65%,_white)_0%,_transparent_45%)] px-4">
<Card className="w-full max-w-md border-border/70 bg-background/95 shadow-sm backdrop-blur">
<CardHeader className="gap-5 text-center">
<div className="mx-auto flex items-center gap-3">
<Logo />
<div className="text-left">
<p className="text-xs font-medium tracking-[0.28em] text-muted-foreground uppercase">
QuickHub
</p>
<p className="text-sm text-muted-foreground">Placeholder logo</p>
<main className="isolate min-h-dvh bg-background">
<div className="grid min-h-dvh lg:grid-cols-[35fr_65fr]">
<section className="flex min-h-dvh bg-background px-6 py-8 sm:px-10 sm:py-10 lg:px-16 lg:py-12 xl:px-20">
<div className="mx-auto flex w-full max-w-xs flex-1 flex-col justify-between gap-10">
<div className="flex items-center gap-3">
<Logo className="size-9 text-foreground" />
<div>
<p className="text-base font-medium text-foreground sm:text-sm">
QuickHub
</p>
<p className="text-base text-muted-foreground sm:text-sm">
Review workspace
</p>
</div>
</div>

<div className="space-y-6">
<div>
<h1 className="w-full text-3xl font-semibold tracking-tight text-balance text-foreground sm:text-2xl">
Review your GitHub work in one place
</h1>
</div>

<form
className="space-y-3"
onSubmit={(event) => {
event.preventDefault();
void signIn.social({ provider: "github" });
}}
>
<Button
type="submit"
size="lg"
iconLeft={<GitHubLogo />}
className="h-11 w-full rounded-lg text-base sm:h-9 sm:text-[13px]"
>
Continue with GitHub
</Button>
</form>
</div>

<div className="flex items-center gap-2 text-base text-muted-foreground sm:text-sm">
<span
aria-hidden="true"
className="size-1.5 rounded-full bg-border"
/>
<p>Simple now, room to layer more later.</p>
</div>
</div>
</section>

<section className="hidden min-h-dvh items-center overflow-hidden bg-background py-4 pl-4 lg:flex lg:py-6 lg:pl-6 xl:py-8 xl:pl-8">
<div className="[-webkit-mask-image:linear-gradient(to_right,black_0,black_80%,transparent_100%)] [mask-image:linear-gradient(to_right,black_0,black_80%,transparent_100%)] flex w-[114%] shrink-0 translate-x-20 items-center justify-center rounded-[2rem] bg-background p-6 shadow-[0_24px_80px_-48px_rgba(15,23,42,0.3)] dark:shadow-none xl:translate-x-32">
<div className="flex aspect-[16/10] w-full max-w-[56rem] items-center justify-center rounded-[1.5rem] border border-border bg-card shadow-[0_18px_40px_-34px_rgba(15,23,42,0.25)] dark:shadow-none xl:max-w-[64rem]">
<div
aria-hidden="true"
className="h-full w-full rounded-[1.2rem]"
/>
</div>
</div>
<CardTitle className="text-2xl tracking-tight sm:text-3xl">
Sign in to QuickHub
</CardTitle>
<CardDescription className="text-base">
Connect GitHub to start from the imported Circle base theme and grow
your own workflow from there.
</CardDescription>
</CardHeader>
<CardContent>
<Button
type="button"
size="lg"
className="w-full"
onClick={() => signIn.social({ provider: "github" })}
>
Continue with GitHub
</Button>
</CardContent>
</Card>
</section>
</div>
</main>
);
}
53 changes: 53 additions & 0 deletions packages/icons/src/brand-logos.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type * as React from "react";

function withClassName(className?: string) {
return className ? `shrink-0 ${className}` : "shrink-0";
}

// Source: https://api.svgl.app?search=github
// Assets:
// - https://svgl.app/library/github_light.svg
// - https://svgl.app/library/github_wordmark_light.svg
export function GitHubLogo(props: React.ComponentProps<"svg">) {
const { className, ...rest } = props;

return (
<svg
aria-hidden="true"
className={withClassName(className)}
fill="none"
focusable="false"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
<path
clipRule="evenodd"
d="M512 0C229.12 0 0 229.12 0 512c0 226.56 146.56 417.92 350.08 485.76 25.6 4.48 35.2-10.88 35.2-24.32 0-12.16-.64-52.48-.64-95.36-128.64 23.68-161.92-31.36-172.16-60.16-5.76-14.72-30.72-60.16-52.48-72.32-17.92-9.6-43.52-33.28-.64-33.92 40.32-.64 69.12 37.12 78.72 52.48 46.08 77.44 119.68 55.68 149.12 42.24 4.48-33.28 17.92-55.68 32.64-68.48-113.92-12.8-232.96-56.96-232.96-252.8 0-55.68 19.84-101.76 52.48-137.6-5.12-12.8-23.04-65.28 5.12-135.68 0 0 42.88-13.44 140.8 52.48 40.96-11.52 84.48-17.28 128-17.28s87.04 5.76 128 17.28c97.92-66.56 140.8-52.48 140.8-52.48 28.16 70.4 10.24 122.88 5.12 135.68 32.64 35.84 52.48 81.28 52.48 137.6 0 196.48-119.68 240-233.6 252.8 18.56 16 34.56 46.72 34.56 94.72 0 68.48-.64 123.52-.64 140.8 0 13.44 9.6 29.44 35.2 24.32C877.44 929.92 1024 737.92 1024 512 1024 229.12 794.88 0 512 0"
fill="currentColor"
fillRule="evenodd"
/>
</svg>
);
}

export function GitHubWordmarkLogo(props: React.ComponentProps<"svg">) {
const { className, ...rest } = props;

return (
<svg
aria-hidden="true"
className={withClassName(className)}
fill="none"
focusable="false"
viewBox="0 0 249.1 67.5"
xmlns="http://www.w3.org/2000/svg"
{...rest}
>
<path
d="M103.4 55.9h-.1s0 .1.1 0m0 .1c-.5 0-1.8.3-3.2.3-4.4 0-5.9-2-5.9-4.6V34.2h8.9c.5 0 .9-.4.9-1.1v-9.5c0-.5-.4-.9-.9-.9h-8.9V10.9c0-.4-.3-.7-.8-.7h-12c-.5 0-.8.3-.8.7V23s-6.1 1.5-6.5 1.6-.7.5-.7.9v7.6c0 .6.4 1.1.9 1.1h6.2v18.3c0 13.6 9.5 15 16 15 3 0 6.5-.9 7.1-1.2.3-.1.5-.5.5-.9V57c0-.5-.4-.9-.8-1m132.1-12.3c0-10.1-4.1-11.4-8.4-11-3.3.2-6 1.9-6 1.9v19.6s2.7 1.9 6.8 2c5.8.2 7.6-1.8 7.6-12.5m13.6-.9c0 19.1-6.2 24.6-17 24.6-9.1 0-14.1-4.6-14.1-4.6s-.2 2.6-.5 2.9c-.2.3-.4.4-.8.4h-8.3c-.6 0-1.1-.4-1.1-.9l.1-62c0-.5.4-.9.9-.9h11.9c.5 0 .9.4.9.9l-.1 20.9s4.6-3 11.3-3h.1c6.8.1 16.7 2.6 16.7 21.7m-48.6-20.1h-11.7c-.6 0-.9.4-.9 1.1v30.3s-3.1 2.2-7.3 2.2-5.4-1.9-5.4-6.1V23.7c0-.5-.4-.9-.9-.9h-11.9c-.5 0-.9.4-.9.9v28.5c0 12.3 6.9 15.3 16.3 15.3 7.8 0 14.1-4.3 14.1-4.3s.3 2.2.4 2.5.5.5.9.5h7.5c.6 0 .9-.4.9-.9l.1-41.7c-.2-.5-.6-.9-1.2-.9m-132.2-.1H56.4c-.5 0-.9.5-.9 1.1v40.9c0 1.1.7 1.5 1.7 1.5h10.7c1.1 0 1.4-.5 1.4-1.5v-41c-.1-.5-.5-1-1-1M62.4 3.8c-4.3 0-7.7 3.4-7.7 7.7s3.4 7.7 7.7 7.7c4.2 0 7.6-3.4 7.6-7.7s-3.4-7.7-7.6-7.7m92-1.4h-11.8c-.5 0-.9.4-.9.9v22.8h-18.5V3.3c0-.5-.4-.9-.9-.9h-11.9c-.5 0-.9.4-.9.9v62c0 .5.5.9.9.9h11.9c.5 0 .9-.4.9-.9V38.8h18.5l-.1 26.5c0 .5.4.9.9.9h11.9c.5 0 .9-.4.9-.9v-62c0-.5-.4-.9-.9-.9M49.1 29.8v32c0 .2-.1.6-.3.7 0 0-7 5-18.5 5-13.8 0-30.3-4.3-30.3-33C0 5.9 14.4-.1 28.4 0c12.2 0 17.1 2.7 17.8 3.2.2.3.3.5.3.8l-2.3 9.9c0 .5-.5 1.1-1.1.9-2-.6-5-1.8-12.1-1.8-8.2 0-17 2.3-17 20.8s8.4 20.6 14.4 20.6c5.1 0 7-.6 7-.6V41.1h-8.2c-.6 0-1.1-.4-1.1-.9V29.8c0-.5.4-.9 1.1-.9h20.9c.6 0 1 .4 1 .9"
fill="currentColor"
/>
</svg>
);
}
1 change: 1 addition & 0 deletions packages/icons/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ export {
Settings01Icon as SettingsIcon,
Sun01Icon as SunIcon,
} from "@hugeicons/react";
export { GitHubLogo, GitHubWordmarkLogo } from "./brand-logos";
43 changes: 36 additions & 7 deletions packages/ui/src/components/button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Slot } from "@radix-ui/react-slot";
import { Slot, Slottable } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";

Expand All @@ -21,11 +21,11 @@ const buttonVariants = cva(
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2 has-[>svg]:px-3",
xxs: "h-6 rounded-md gap-1.5 px-2.5 has-[>svg]:px-2",
xs: "h-7 rounded-md gap-1.5 px-2.5 has-[>svg]:px-2",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
default: "h-9 px-4 py-2",
xxs: "h-6 rounded-md gap-1.5 px-2.5",
xs: "h-7 rounded-md gap-1.5 px-2.5",
sm: "h-8 rounded-md gap-1.5 px-3",
lg: "h-10 rounded-md px-6",
icon: "size-9",
},
},
Expand All @@ -36,15 +36,22 @@ const buttonVariants = cva(
},
);

type ButtonIcon = React.ReactNode;

function Button({
children,
className,
variant,
size,
asChild = false,
iconLeft,
iconRight,
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean;
iconLeft?: ButtonIcon;
iconRight?: ButtonIcon;
}) {
const Comp = asChild ? Slot : "button";

Expand All @@ -53,7 +60,29 @@ function Button({
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
>
{iconLeft ? (
<span
data-slot="button-icon"
data-side="left"
aria-hidden="true"
className="shrink-0"
>
{iconLeft}
</span>
) : null}
<Slottable>{children}</Slottable>
{iconRight ? (
<span
data-slot="button-icon"
data-side="right"
aria-hidden="true"
className="shrink-0"
>
{iconRight}
</span>
) : null}
</Comp>
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,14 @@ function SidebarTrigger({
data-slot="sidebar-trigger"
variant="ghost"
size="icon"
iconLeft={<PanelLeftIcon />}
className={cn("h-7 w-7", className)}
onClick={(event) => {
onClick?.(event);
toggleSidebar();
}}
{...props}
>
<PanelLeftIcon />
<span className="sr-only">Toggle Sidebar</span>
</Button>
);
Expand Down