Skip to content

Commit

Permalink
Merge pull request #110 from bleu/juliano/op-662-ensure-quest-page-ma…
Browse files Browse the repository at this point in the history
…tches-design-spec

Quest page
  • Loading branch information
juliano-quatrin-nunes authored Jan 10, 2025
2 parents c866c42 + 3d3f4c4 commit ca009c8
Show file tree
Hide file tree
Showing 34 changed files with 558 additions and 341 deletions.
2 changes: 1 addition & 1 deletion apps/govquests-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"@0no-co/graphqlsp": "^1.12.16",
"@tailwindcss/typography": "^0.5.15",
"@types/node": "^22",
"@types/react": "npm:[email protected]alpha.3",
"@types/react": "npm:[email protected]rc.1",
"@types/react-dom": "npm:[email protected]",
"biome": "^0.3.3",
"lint-staged": "^15.3.0",
Expand Down
9 changes: 9 additions & 0 deletions apps/govquests-frontend/public/backgrounds/first_tier.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/govquests-frontend/public/badge/quest1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions apps/govquests-frontend/public/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions apps/govquests-frontend/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

.dark {
/* Optimism-inspired colors for dark mode */
--background: 230 11% 11%; /* Dark background #191B1F */
--background: 228 9% 11%; /* Dark background #1a1b1f */
--foreground: 0 0% 100%;

--card: 230 11% 11%;
Expand All @@ -54,8 +54,8 @@
--popover: 230 11% 11%;
--popover-foreground: 0 0% 100%;

--primary: 352 100% 50%; /* Optimism Red */
--primary-foreground: 0 0% 100%;
--primary: 0 0% 100%; /* White */
--primary-foreground: 0 0% 0% /* Black text */;

--secondary: 228 9% 23%; /* Dark grey #333640 */
--secondary-foreground: 0 0% 100%;
Expand Down
2 changes: 1 addition & 1 deletion apps/govquests-frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function RootLayout({
return (
<html
className={cn(
"bg-background text-foreground h-full",
"bg-background text-foreground h-full dark",
jetBrains.className,
)}
lang="en"
Expand Down
35 changes: 16 additions & 19 deletions apps/govquests-frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import SignInButton from "@/domains/authentication/components/SignInButton";
import { NotificationBell } from "@/domains/notifications/components/NotificationBell";
import { cn } from "@/lib/utils";
import { HomeIcon, MapIcon, StarIcon } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import type React from "react";
Expand All @@ -12,51 +13,47 @@ const Header: React.FC = () => {
const currentPath = usePathname();

return (
<header className="p-8">
<header className="p-8 pr-16">
<div className="flex justify-between items-center">
<Link
href="/"
className="bg-primary text-foreground px-12 py-1 rounded-md"
>
Logo
<Link href="/" className="text-foreground py-1 rounded-md">
<Image src="/logo.svg" alt="logo" width={200} height={200} />
</Link>

<nav className="bg-primary rounded-lg">
<nav>
<ul className="flex space-x-5 px-1 py-1">
<li>
<Link
className={cn(
"flex items-center text-foreground px-3 py-1 rounded-full hover:bg-primary/70 transition",
currentPath.startsWith("/quests") && "font-bold",
"flex items-center text-foreground/80 px-3 py-1 rounded-full transition hover:scale-110",
currentPath.startsWith("/quests") &&
"font-black text-foreground",
)}
href="/quests"
>
<MapIcon className="w-4 h-4 mr-1" />
Quests
# Quests
</Link>
</li>
<li>
<Link
className={cn(
"flex items-center text-foreground px-3 py-1 rounded-full hover:bg-primary/70 transition",
currentPath === "/" && "font-bold",
"flex items-center text-foreground/80 px-3 py-1 rounded-full transition hover:scale-110",
currentPath === "/" && "font-black text-foreground",
)}
href="/"
>
<HomeIcon className="w-4 h-4 mr-1" />
Home
# Achievements
</Link>
</li>
<li>
<Link
className={cn(
"flex items-center text-foreground px-3 py-1 rounded-full hover:bg-primary/70 transition",
currentPath.startsWith("/leaderboard") && "font-bold",
"flex items-center text-foreground/80 px-3 py-1 rounded-full transition hover:scale-110",
currentPath.startsWith("/leaderboard") &&
"font-black text-foreground",
)}
href="/leaderboard"
>
<StarIcon className="w-4 h-4 mr-1" />
Leaderboard
# Leaderboard
</Link>
</li>
</ul>
Expand Down
29 changes: 29 additions & 0 deletions apps/govquests-frontend/src/components/IndicatorPill.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { cn } from "@/lib/utils";
import { ComponentProps } from "react";

export const IndicatorPill = ({
className,
...props
}: ComponentProps<"span">) => {
return (
<div className="relative border shadow-[1px_1px_0px_0px_#000000] bg-primary border-primary-foreground items-center text-center rounded-lg justify-center flex py-1 px-4">
<AnchorPoint className="absolute top-1 left-1 " />
<span
className="text-primary-foreground text-xs font-bold whitespace-nowrap flex items-center"
{...props}
/>
<AnchorPoint className="absolute top-1 right-1 " />
</div>
);
};

const AnchorPoint = ({ className }: { className: string }) => {
return (
<div
className={cn(
"size-[5px] border-[1.5px] border-primary-foreground rounded-full shadow-[0.5px_0.5px_0px_0px_#0000004D]",
className,
)}
/>
);
};
13 changes: 12 additions & 1 deletion apps/govquests-frontend/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { config, siweConfig } from "@/wagmi";
import Header from "./Header";
import { Toaster } from "./ui/toaster";
import { useNotificationProcessor } from "@/domains/notifications/hooks/useNotificationProcessor";
import Image from "next/image";

export const queryClient = new QueryClient();

Expand All @@ -32,7 +33,17 @@ export default function Layout({
}>) {
return (
<Providers>
<div className="h-full">{children}</div>
<div className="h-full relative">
<Image
src="/backgrounds/first_tier.svg"
width={1000}
height={1000}
className="object-cover fixed size-full"
alt="background_tier"
/>
<div className="fixed object-cover size-full z-[1] bg-gradient-to-b from-[#1A1B1F] via-[rgba(26,27,31,0.9)] via-[rgba(26,27,31,0.8)] via-[rgba(26,27,31,0.7)] to-[rgba(26,27,31,0.6)]" />
<div className="relative z-10">{children}</div>
</div>
<Toaster />
</Providers>
);
Expand Down
11 changes: 3 additions & 8 deletions apps/govquests-frontend/src/components/RewardIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Rewards } from "@/domains/questing/types/questTypes";
import { cn } from "@/lib/utils";
import Image from "next/image";
import type React from "react";
import { IndicatorPill } from "./IndicatorPill";

interface RewardIndicator {
reward: Pick<Rewards[number], "amount" | "type">;
Expand All @@ -10,19 +10,14 @@ interface RewardIndicator {

const RewardIndicator: React.FC<RewardIndicator> = ({ reward, className }) => {
return (
<span
className={cn(
"bg-secondary font-normal py-1 px-2 rounded-md text-sm ml-1 flex gap-1 p-auto w-21",
className,
)}
>
<IndicatorPill className={className}>
{reward.amount}{" "}
{reward.type == "Token" ? (
<Image src="/opTokenIcon.svg" alt="OP Icon" width={12} height={12} />
) : (
reward.type
)}
</span>
</IndicatorPill>
);
};

Expand Down
22 changes: 22 additions & 0 deletions apps/govquests-frontend/src/components/ui/DividerHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { cn } from "@/lib/utils";
import { ComponentProps, ReactNode } from "react";

export const DividerHeader = ({
children,
className,
}: ComponentProps<"div">) => {
return (
<div className="flex items-center justify-center w-full gap-9">
<div className="border-b h-0 w-full" />
<div
className={cn(
"text-xl font-medium text-foreground/50 whitespace-nowrap",
className,
)}
>
{children}
</div>
<div className="border-b h-0 w-full" />
</div>
);
};
4 changes: 2 additions & 2 deletions apps/govquests-frontend/src/components/ui/HtmlRender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ const HtmlRender: React.FC<HtmlRenderProps> = ({ content }) => {
return (
<div
className={cn(
"prose prose-sm max-w-none",
"prose-a:underline",
"prose prose-sm max-w-none font-thin text-foreground/80",
"prose-a:underline prose-a:text-foreground/80",
"prose-strong:font-bold prose-strong:text-inherit",
"prose-ul:list-disc prose-ul:pl-5 prose-ul:mt-0",
"prose-li:pl-0 prose-li:my-0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ function ActionButton<T extends ActionType>({
variant="secondary"
size="sm"
className={cn(
"mr-6",
disabled && "pointer-events-none",
status === "completed" && "opacity-50",
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@ import { useFetchQuest } from "@/domains/questing/hooks/useFetchQuest";
import { Action } from "@/domains/questing/types/questTypes";
import React from "react";
import { ActionStrategyFactory } from "../strategies/ActionStrategyFactory";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";

interface ActionHandlerProps {
questSlug: string;
action: Action;
actionIndex: number;
}

const ActionHandler: React.FC<ActionHandlerProps> = ({ questSlug, action }) => {
const ActionHandler: React.FC<ActionHandlerProps> = ({
questSlug,
action,
actionIndex,
}) => {
const { data, isLoading, refetch } = useFetchQuest(questSlug);

const quest = data?.quest || null;
Expand All @@ -27,13 +38,29 @@ const ActionHandler: React.FC<ActionHandlerProps> = ({ questSlug, action }) => {
}

return (
<StrategyComponent
questSlug={questSlug}
questId={quest.id}
action={action}
execution={execution}
refetch={refetch}
/>
<Accordion
type="single"
collapsible
className="border rounded-lg py-0 bg-background/60"
>
<AccordionItem value="item-1" className="px-10">
<AccordionTrigger className="py-4">
<span className="text-lg font-semibold mb-1 py-0 flex gap-2">
<span className="opacity-60">#{actionIndex + 1}</span>
{action.displayData.title}
</span>
</AccordionTrigger>
<AccordionContent>
<StrategyComponent
questSlug={questSlug}
questId={quest.id}
action={action}
execution={execution}
refetch={refetch}
/>
</AccordionContent>
</AccordionItem>
</Accordion>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,17 @@ interface ActionListProps {

const ActionList: React.FC<ActionListProps> = ({ questSlug, actions }) => {
return (
<div>
<div className="flex flex-col gap-5">
{actions.every((action) => action.actionType === "read_document") && (
<h4 className="mb-5 text-xl font-semibold">Read</h4>
<h4 className="text-xl font-semibold">Read</h4>
)}
{actions.map((action, index) => (
<div
key={action.id}
className={cn(
"border-t-2 py-7",
index === 0 && "border-b-2 border-transparent",
)}
>
<ActionHandler questSlug={questSlug} action={action} />
<div key={action.id}>
<ActionHandler
questSlug={questSlug}
action={action}
actionIndex={index}
/>
</div>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useSIWE } from "connectkit";
import React, { useCallback } from "react";
import React, { ComponentProps, useCallback } from "react";
import { useAccount } from "wagmi";
import { useCompleteActionExecution } from "../hooks/useCompleteActionExecution";
import { useStartActionExecution } from "../hooks/useStartActionExecution";
Expand Down Expand Up @@ -118,3 +118,21 @@ export const BaseStrategy = (props: BaseStrategyProps) => {

return <>{children({ ...contextValue, ...props })}</>;
};

export const ActionContent = (props: ComponentProps<"div">) => {
return (
<div
className="flex flex-col justify-between items-start gap-5"
{...props}
/>
);
};

export const ActionFooter = (props: ComponentProps<"div">) => {
return (
<div
className="self-end mb-2 flex flex-col gap-1 items-end [&>button]:w-52 [&>span]:text-xs"
{...props}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCallback, useMemo, useState } from "react";
import ActionButton from "../components/ActionButton";
import { ActionType, VerifyWalletStatus } from "../types/actionButtonTypes";
import { ActionStrategy, StrategyChildComponent } from "./ActionStrategy";
import { BaseStrategy } from "./BaseStrategy";
import { ActionContent, ActionFooter, BaseStrategy } from "./BaseStrategy";

export const DefaultStrategy: ActionStrategy = (props) => {
const [errorMessage, setErrorMessage] = useState<string>();
Expand Down Expand Up @@ -53,18 +53,16 @@ const DefaultContent: StrategyChildComponent = ({
],
);
return (
<div className="flex flex-1 justify-between items-center">
<div className="flex flex-col">
<span className="text-xl font-semibold mb-1">
{action.displayData.title}
</span>

<ActionContent>
<div className="text-sm">
<HtmlRender content={action.displayData.description || ""} />
</div>
<ActionFooter>
<ActionButton {...buttonProps} />
{errorMessage && (
<span className="text-sm font-bold">{errorMessage}</span>
<span className="text-xs font-bold self-end">{errorMessage}</span>
)}
</div>
<ActionButton {...buttonProps} />
</div>
</ActionFooter>
</ActionContent>
);
};
Loading

0 comments on commit ca009c8

Please sign in to comment.