💄 Update poll page (#1672)

This commit is contained in:
Luke Vella 2025-04-17 17:21:19 +01:00 committed by GitHub
parent 12651abd0c
commit cf90e7a6df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 95 additions and 55 deletions

View file

@ -1,6 +1,6 @@
import type { PollStatus } from "@rallly/database"; import type { PollStatus } from "@rallly/database";
import { Button } from "@rallly/ui/button"; import { Button } from "@rallly/ui/button";
import { shortUrl } from "@rallly/utils/absolute-url"; import { absoluteUrl, shortUrl } from "@rallly/utils/absolute-url";
import { InboxIcon } from "lucide-react"; import { InboxIcon } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { z } from "zod"; import { z } from "zod";
@ -186,6 +186,7 @@ export default async function Page({
title={poll.title} title={poll.title}
status={poll.status} status={poll.status}
participants={poll.participants} participants={poll.participants}
pollLink={absoluteUrl(`/poll/${poll.id}`)}
inviteLink={shortUrl(`/invite/${poll.id}`)} inviteLink={shortUrl(`/invite/${poll.id}`)}
/> />
))} ))}

View file

@ -54,10 +54,11 @@ export function InvitePage() {
const poll = usePoll(); const poll = usePoll();
return ( return (
<div className="mx-auto max-w-4xl space-y-3 p-3 lg:space-y-4 lg:px-4 lg:py-8"> <div>
{/* Track poll views */}
<PollViewTracker pollId={poll.id} /> <PollViewTracker pollId={poll.id} />
<PollHeader /> <PollHeader />
<div className="p-3">
<div className="mx-auto w-full max-w-4xl space-y-4">
<GoToApp /> <GoToApp />
<EventCard /> <EventCard />
<ScheduledEvent /> <ScheduledEvent />
@ -67,5 +68,7 @@ export function InvitePage() {
<Discussion /> <Discussion />
<PollFooter /> <PollFooter />
</div> </div>
</div>
</div>
); );
} }

View file

@ -2,7 +2,6 @@
import Discussion from "@/components/discussion"; import Discussion from "@/components/discussion";
import { EventCard } from "@/components/event-card"; import { EventCard } from "@/components/event-card";
import { PollFooter } from "@/components/poll/poll-footer"; import { PollFooter } from "@/components/poll/poll-footer";
import { PollHeader } from "@/components/poll/poll-header";
import { PollViewTracker } from "@/components/poll/poll-view-tracker"; import { PollViewTracker } from "@/components/poll/poll-view-tracker";
import { ResponsiveResults } from "@/components/poll/responsive-results"; import { ResponsiveResults } from "@/components/poll/responsive-results";
import { ScheduledEvent } from "@/components/poll/scheduled-event"; import { ScheduledEvent } from "@/components/poll/scheduled-event";
@ -21,7 +20,6 @@ export function AdminPage() {
{/* Track poll views */} {/* Track poll views */}
<PollViewTracker pollId={poll.id} /> <PollViewTracker pollId={poll.id} />
<UnsubscribeAlert /> <UnsubscribeAlert />
<PollHeader />
<GuestPollAlert /> <GuestPollAlert />
<EventCard /> <EventCard />
<ScheduledEvent /> <ScheduledEvent />

View file

@ -7,14 +7,12 @@ import {
LogInIcon, LogInIcon,
LogOutIcon, LogOutIcon,
ShieldCloseIcon, ShieldCloseIcon,
XIcon,
} from "lucide-react"; } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { useParams, usePathname } from "next/navigation"; import { useParams, usePathname } from "next/navigation";
import React from "react"; import React from "react";
import { LogoutButton } from "@/app/components/logout-button"; import { LogoutButton } from "@/app/components/logout-button";
import { PollPageIcon } from "@/app/components/page-icons";
import { InviteDialog } from "@/components/invite-dialog"; import { InviteDialog } from "@/components/invite-dialog";
import { LoginLink } from "@/components/login-link"; import { LoginLink } from "@/components/login-link";
import { import {
@ -46,15 +44,19 @@ const Layout = ({ children }: React.PropsWithChildren) => {
const pollLink = `/poll/${poll.id}`; const pollLink = `/poll/${poll.id}`;
const pathname = usePathname(); const pathname = usePathname();
return ( return (
<div className="bg-gray-100"> <div>
<div className="sticky top-0 z-30 flex flex-col justify-between gap-x-4 gap-y-2.5 border-b bg-gray-100 p-3 sm:flex-row lg:items-center lg:px-5"> <div className="sticky top-0 z-30 border-b bg-gray-100/90 p-3 backdrop-blur-md sm:flex-row">
<div className="mx-auto flex max-w-4xl justify-between">
<div className="flex min-w-0 items-center gap-x-2.5"> <div className="flex min-w-0 items-center gap-x-2.5">
{pathname === pollLink ? ( {pathname === pollLink ? (
<Button variant="ghost" asChild> <Button variant="ghost" asChild>
<Link href="/polls"> <Link href="/polls">
<Icon> <Icon>
<XIcon /> <ArrowLeftIcon />
</Icon> </Icon>
<span>
<Trans i18nKey="back" defaults="Back" />
</span>
</Link> </Link>
</Button> </Button>
) : ( ) : (
@ -63,20 +65,20 @@ const Layout = ({ children }: React.PropsWithChildren) => {
<Icon> <Icon>
<ArrowLeftIcon /> <ArrowLeftIcon />
</Icon> </Icon>
<span>
<Trans i18nKey="back" defaults="Back" />
</span>
</Link> </Link>
</Button> </Button>
)} )}
<div>
<PollPageIcon size="sm" />
</div>
<h1 className="truncate text-sm font-semibold">{poll.title}</h1>
</div> </div>
<div> <div>
<AdminControls /> <AdminControls />
</div> </div>
</div> </div>
<div className="mx-auto max-w-4xl space-y-3 p-3 lg:space-y-4 lg:px-4 lg:py-8"> </div>
{children} <div className="p-3">
<div className="mx-auto max-w-4xl space-y-3">{children}</div>
</div> </div>
</div> </div>
); );

View file

@ -151,11 +151,13 @@ const ManagePoll: React.FunctionComponent<{
<> <>
<DropdownMenu modal={false}> <DropdownMenu modal={false}>
<DropdownMenuTrigger asChild={true}> <DropdownMenuTrigger asChild={true}>
<Button disabled={disabled}> <Button variant="ghost" disabled={disabled}>
<Icon> <Icon>
<SettingsIcon /> <SettingsIcon />
</Icon> </Icon>
<span className="hidden sm:block">
<Trans i18nKey="manage" /> <Trans i18nKey="manage" />
</span>
<Icon> <Icon>
<ChevronDownIcon /> <ChevronDownIcon />
</Icon> </Icon>

View file

@ -83,7 +83,7 @@ const NotificationsToggle: React.FunctionComponent = () => {
<Button <Button
data-testid="notifications-toggle" data-testid="notifications-toggle"
disabled={user.isGuest} disabled={user.isGuest}
className="flex items-center gap-2 px-2.5" variant="ghost"
onClick={async () => { onClick={async () => {
if (user.isGuest) { if (user.isGuest) {
signIn(); signIn();

View file

@ -4,7 +4,7 @@ import { Trans } from "@/components/trans";
export function PollFooter() { export function PollFooter() {
return ( return (
<div className="py-4 text-center text-sm text-gray-500"> <div className="pb-12 pt-4 text-center text-sm text-gray-500">
<Trans <Trans
defaults="Powered by <a>{name}</a>" defaults="Powered by <a>{name}</a>"
i18nKey="poweredByRallly" i18nKey="poweredByRallly"

View file

@ -1,14 +1,46 @@
import { LogoLink } from "@/app/components/logo-link"; import { Button } from "@rallly/ui/button";
import Image from "next/image";
import Link from "next/link";
import { UserDropdown } from "@/components/user-dropdown"; import { UserDropdown } from "@/components/user-dropdown";
import { useUser } from "../user-provider";
export function PollHeader() { export function PollHeader() {
const { user } = useUser();
return ( return (
<div className="flex items-center justify-between"> <div className="sticky top-0 z-30 border-b bg-gray-100/90 p-3 backdrop-blur-md">
<div className="mx-auto flex max-w-4xl items-center justify-between">
<div className="flex items-center gap-x-2.5"> <div className="flex items-center gap-x-2.5">
<LogoLink /> <Link
className="transition-transform active:translate-y-1"
href="https://rallly.co"
>
<Image
src="/images/logo-mark.svg"
alt="Rallly"
width={32}
height={32}
priority={true}
className="shrink-0"
/>
<span className="sr-only">Rallly</span>
</Link>
</div> </div>
<div className="flex items-center gap-x-2.5"> <div className="flex items-center gap-x-2.5">
{user.email ? (
<UserDropdown /> <UserDropdown />
) : (
<>
<Button variant="ghost" asChild>
<Link href="/login">Login</Link>
</Button>
<Button variant="primary" asChild>
<Link href="/register">Sign Up</Link>
</Button>
</>
)}
</div>
</div> </div>
</div> </div>
); );

View file

@ -14,11 +14,13 @@ export function PollListItem({
status, status,
participants, participants,
inviteLink, inviteLink,
pollLink,
}: { }: {
title: string; title: string;
status: PollStatus; status: PollStatus;
participants: { id: string; name: string; image?: string }[]; participants: { id: string; name: string; image?: string }[];
inviteLink: string; inviteLink: string;
pollLink: string;
}) { }) {
return ( return (
<StackedListItem> <StackedListItem>
@ -26,7 +28,7 @@ export function PollListItem({
<PollStatusIcon status={status} showTooltip={false} /> <PollStatusIcon status={status} showTooltip={false} />
<Link <Link
className="focus:ring-ring min-w-0 text-sm font-medium hover:underline focus-visible:ring-2" className="focus:ring-ring min-w-0 text-sm font-medium hover:underline focus-visible:ring-2"
href={inviteLink} href={pollLink}
> >
<span className="absolute inset-0" /> <span className="absolute inset-0" />
<span className="block truncate">{title}</span> <span className="block truncate">{title}</span>