Skip to content

Commit

Permalink
Build UI (#22)
Browse files Browse the repository at this point in the history
* setup default ui build

* --

* UI: add theme, layouts & first pass at homepage

* refactored web3 wallet providers

* add theme colors, fixed up sidebar

* top navbar styling

* wip

* added post-card

* update homepage

* fixed up right sidebar

* cleaned up tabs

* fix build error

* started read post & create post screens

* add screen to create a post

* add user profile screen
  • Loading branch information
od41 authored Nov 16, 2023
1 parent e67eed2 commit 3b759de
Show file tree
Hide file tree
Showing 23 changed files with 1,270 additions and 11 deletions.
12 changes: 11 additions & 1 deletion frontend/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@
},
"dependencies": {
"@auth/firebase-adapter": "^1.0.4",
"@hookform/resolvers": "^3.3.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-toggle": "^1.0.3",
"@rainbow-me/rainbowkit": "^1.1.4",
"@rainbow-me/rainbowkit-siwe-next-auth": "^0.3.2",
"@tiptap/extension-placeholder": "^2.1.12",
"@tiptap/pm": "^2.1.12",
"@tiptap/react": "^2.1.12",
"@tiptap/starter-kit": "^2.1.12",
"axios": "^1.6.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
Expand All @@ -30,12 +38,14 @@
"prettier": "^3.0.3",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.48.2",
"react-icons": "^4.11.0",
"siwe": "^2.1.4",
"tailwind-merge": "^2.0.0",
"tailwindcss-animate": "^1.0.7",
"viem": "^1.18.1",
"wagmi": "^1.4.5"
"wagmi": "^1.4.5",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/node": "^20",
Expand Down
14 changes: 8 additions & 6 deletions frontend/nextjs/src/app/dapp/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@ import '@rainbow-me/rainbowkit/styles.css';
import {
ConnectButton
} from '@rainbow-me/rainbowkit';
import { Sidebar } from './components/sidebar';
import { RightSidebar } from './components/right-sidebar';
import { Sidebar } from './_components/sidebar';
import { RightSidebar } from './_components/right-sidebar';
import { Search } from '@/components/ui/forms/search';
import { Button } from '@/components/ui/button';
import { HiOutlinePencilAlt } from "react-icons/hi"
import DappProviders from './components/providers';
import DappProviders from './_components/providers';
import SessionProvider from "@/lib/hooks/sessionProvider";
import { getServerSession } from "next-auth";
export const metadata: Metadata = {
title: 'MEMM! Homepage',
}

type Props = {
children: React.ReactNode
}

export default async function DappLayout({
children
}: {
children: React.ReactNode
}) {
}: Props) {
const session = await getServerSession();
return (
<>
Expand Down
221 changes: 221 additions & 0 deletions frontend/nextjs/src/app/dapp/p/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import React from 'react'
import { HiCheckBadge, HiOutlineHandThumbUp, HiOutlineHandThumbDown, HiOutlineShare, HiOutlineFire } from 'react-icons/hi2'
import Image from 'next/image'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import { Card, CardHeader, CardContent, CardTitle, CardDescription, CardFooter } from '@/components/ui/card'
import { Separator } from '@/components/ui/separator'
import { Badge } from '@/components/ui/badge'
import { ScrollArea } from '@/components/ui/scroll-area'
import { RightSidebar } from '../../_components/right-sidebar'

const Post = ({ params }: { params: { slug: string } }) => {
const post = {
title: "I’m an experienced CEO. I applied for 1001 positions. This is what happened.",
body: `Facilisi at lorem semper eget. Eget posuere dictumst velit lacus est. Fringilla quam sollicitudin diam sollicitudin magna. Arcu ullamcorper nisl at aliquet luctus. Vitae commodo dictum sed et. In ultrices eu curabitur neque pulvinar ac eget ullamcorper lorem. Velit vitae id sit gravida mi viverra. Non ipsum nunc sed risus fermentum sed in. Lectus donec dignissim diam sed non tortor. Nibh euismod id tincidunt scelerisque cras est. Tincidunt mollis commodo urna scelerisque nibh at sed. Amet odio erat congue diam in.
Elit tellus velit diam suspendisse eget. Sed in et accumsan amet id sed ultrices lorem mollis. Donec tempus sapien pellentesque est pretium et. Ut euismod vitae feugiat donec amet euismod arcu egestas dis. Elementum neque suspendisse facilisis mi ullamcorper purus aliquam adipiscing. Sagittis non tristique sed sed purus magna sem. Integer non habitasse ornare in amet mauris id. Nulla condimentum ipsum aliquam urna vitae consequat. Nec lobortis aenean auctor imperdiet facilisis vel. Cras amet euismod neque dictumst vestibulum. Faucibus orci accumsan ipsum eget nunc magnis elit. Quam ultricies turpis scelerisque aliquet amet enim venenatis non. Iaculis hac in aliquet sed blandit vestibulum etiam. Adipiscing adipiscing augue senectus tempor. Mauris pellentesque consequat aliquet sagittis.
In diam vestibulum eu tellus suspendisse non vestibulum. Ut ipsum risus suscipit amet quam a mi. Pellentesque est in amet in. Vitae urna laoreet non eu. Euismod ut quis elit risus massa. Posuere amet massa pulvinar cursus morbi nibh varius quam proin. Et tortor risus elementum morbi ante tortor adipiscing pretium vestibulum.`,
image: "https://images.unsplash.com/photo-1559136555-9303baea8ebd?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
author: {
name: "Naval",
avatar: "https://images.unsplash.com/photo-1640960543409-dbe56ccc30e2?q=80&w=1480&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
mentor: "true"
},
metadata: {
upvotes: 314,
downvotes: 42
}
}

const topCreatorList = [
{
name: "Naval",
avatar: "https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D",
mentor: "false",
skill: "UI Design",
href: "/profile/naval",
ment: 134
},
{
name: "Naval",
avatar: "https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D",
mentor: "true",
skill: "Java",
href: "/profile/naval",
ment: 693
},
{
name: "Naval",
avatar: "https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D",
mentor: "true",
skill: "Ruby",
href: "/profile/naval",
ment: 953
},
{
name: "Naval",
avatar: "https://images.unsplash.com/photo-1607746882042-944635dfe10e?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D",
mentor: "true",
skill: "AI",
href: "/profile/naval",
ment: 422
},
]

return (
<div className="grid grid-cols-1 md:grid-cols-6 col-span-4">
<div className="h-full px-4 py-6 lg:px-6 col-span-1 md:col-span-4 md:border-x">
<ScrollArea className="h-[90vh] w-full">
<Card className='border-none'>
<CardHeader className='px-0 pt-0'>
<div className='flex items-center'>
<div className="w-10 h-10 relative">
<Image
fill
className='rounded-full object-cover'
loading="eager"
src={post.author.avatar}
alt={`${post.author.name}-avatar`}
quality={80}
/>
</div>
<div className='ml-3'>
<div className="flex items-center">
<p className='text-md text-foreground'>{post.author.name}</p>
{post.author.mentor === "true" && <HiCheckBadge className="w-4 h-4 ml-1 text-accent-3" />}
<div className='ml-2 text-[11px] text-muted'>20 secs. ago</div>
</div>
<Button variant="ghost" className='text-xs px-0 py-0 rounded-sm h-auto hover:bg-transparent hover:text-accent-3 text-muted'>Follow</Button>
</div>
</div>

</CardHeader>
<CardContent className='space-y-5 px-0'>
<div className="w-full h-[400px] relative">
<Image
fill
src={post.image}
className='rounded-md object-cover'
loading="lazy"
alt={`${post.title} cover photo`}
/>
</div>
<CardTitle className='font-bold text-3xl text-foreground tracking-wide'>{post.title}</CardTitle>
<CardDescription className='text-muted text-sm'>{post.body}</CardDescription>
</CardContent>
<Separator className="bg-border mb-3" />
<CardFooter className='pb-0 px-0 flex justify-between'>

<div className='flex items-center'>
<div className="flex items-center">
<Button variant="ghost" aria-label='Upvote a post' size="icon">
<HiOutlineHandThumbUp className="h-5 w-5 text-foreground" />
</Button>
<div className='text-sm text-foreground ml-1'>
{post.metadata.upvotes}
</div>

</div>
<div className="flex items-center ml-2">
<Button variant="ghost" aria-label='Upvote a post' size="icon">
<HiOutlineHandThumbDown className="h-5 w-5 text-foreground" />
</Button>
</div>
</div>

<Button variant="ghost" aria-label='Upvote a post' size="icon">
<HiOutlineShare className="h-5 w-5 text-foreground" />
</Button>
</CardFooter>
</Card>
</ScrollArea>
</div>
<RightSidebar className="hidden md:block min-h-[94vh] col-span-2 lg:col-span-2" >
<>

<div className="mb-8">
<h2 className="mb-1 text-md pl-3 font-semibold tracking-tight">
Top Creators
</h2>
<div className="flex flex-col gap-y-0">
{topCreatorList.map((profile, key) => {
return <Link href={profile.href} key={`top-creator-${key}`} className="px-3 py-2 rounded-md flex w-full items-center justify-between hover:bg-accent-shade">
<div className='flex items-center'>
<div className="w-10 h-10 relative">
<Image
fill
className='rounded-full object-cover'
loading="eager"
src={profile.avatar}
alt={`${profile.name}-avatar`}
quality={80}
/>
</div>
<div className='ml-3'>
<div className="flex items-center">
<p className='text-md text-foreground'>{profile.name}</p>
{profile.mentor === "true" && <HiCheckBadge className="w-4 h-4 ml-1 text-accent-3" />}
</div>
<Badge>{profile.skill}</Badge>
</div>
</div>
<div className="flex items-center text-xs text-muted">
<HiOutlineFire className="w-4 h-4 ml-1 text-muted" />
<div className="ml-1">
245 MENT
</div>
</div>
</Link>
})}


</div>
</div>

<div className="">
<h2 className="mb-1 text-md pl-3 font-semibold tracking-tight">
Who to Follow
</h2>
<div className="flex flex-col gap-y-0">
{topCreatorList.map((profile, key) => {
return <Link href={profile.href} key={`top-creator-${key}`} className="px-3 py-2 rounded-md flex w-full items-center justify-between hover:bg-accent-shade">
<div className='flex items-center'>
<div className="w-10 h-10 relative">
<Image
fill
className='rounded-full object-cover'
loading="eager"
src={profile.avatar}
alt={`${profile.name}-avatar`}
quality={80}
/>
</div>
<div className='ml-3'>
<div className="flex items-center">
<p className='text-md text-foreground'>{profile.name}</p>
{profile.mentor === "true" && <HiCheckBadge className="w-4 h-4 ml-1 text-accent-3" />}
</div>
<Badge>{profile.skill}</Badge>
</div>
</div>
<div className="flex items-center text-xs text-muted">
<HiOutlineFire className="w-4 h-4 ml-1 text-muted" />
<div className="ml-1">
245 MENT
</div>
</div>
</Link>
})}


</div>
</div>
</>
</RightSidebar>
</div>
)
}

export default Post
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client"
import React from 'react'
import * as z from "zod"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"

import { Button } from "@/components/ui/button"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { useToast } from "@/components/ui/use-toast"
import { Textarea } from "@/components/ui/textarea"
import RichTextEditor from '@/components/ui/rich-text-editor'

const formSchema = z.object({
postTitle: z.string().min(1, {
message: "Title can't be empty",
}),
postBody: z.string()
})

const CreatePostForm = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
postTitle: "",
postBody: "",
},
})
const { toast } = useToast()

function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
toast({
description: "Your post has been created",

})
}

return (
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="postTitle"
render={({ field }) => (
<FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input placeholder="Your post title" {...field} />
</FormControl>
<FormMessage className='text-xs text-muted font-normal' />
</FormItem>
)}
/>

<FormField
control={form.control}
name="postBody"
render={({ field }) => (
<FormItem>
<FormLabel>Body</FormLabel>
<FormControl>
<RichTextEditor placeholder="Answer a question or explain a concept" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end w-full">
<Button type="submit" variant='gradient' className='w-[160px] '>Post</Button>
</div>
</form>
</Form>
</div>
)
}

export default CreatePostForm
Loading

0 comments on commit 3b759de

Please sign in to comment.