Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • com3014-coursework/daily-thought-app
1 result
Show changes
Commits on Source (26)
Showing
with 5829 additions and 201 deletions
This diff is collapsed.
......@@ -9,11 +9,15 @@
"lint": "next lint"
},
"dependencies": {
"next": "^13.2.4"
},
"devDependencies": {
"@types/node": "18.15.0",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"eslint": "8.35.0",
"eslint-config-next": "13.2.4",
"next": "13.2.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^4.8.0",
"typescript": "4.9.5"
}
}
import { FC, PropsWithChildren } from 'react';
import styles from '../../styles/NavMenuItem.module.css'
type NavMenuItemProps = {
label: string;
icon: any;
}
const NavMenuItem:FC<PropsWithChildren<NavMenuItemProps>> = ({
label,
icon
}) => {
return (
<div className={styles.menuItem}>
{icon}
<p className={styles.label}>{label}</p>
</div>
)
}
export default NavMenuItem;
\ No newline at end of file
import { Children, FC, PropsWithChildren, useState } from "react";
import styles from '../../styles/NavigationProvider.module.css'
import Avatar from "../profile/avatar";
import NavMenuItem from "./NavMenuItem";
import { AiOutlineUser } from 'react-icons/ai'
type NavProviderProps = {
navState: boolean
}
const NavigationProvider: FC<PropsWithChildren<NavProviderProps>> = ({
children,
navState
}) => {
let colors = ["#ffd0d2","#fffdd0","#d0fffd","#d0d2ff"];
let user = {FirstName: "John", LastName: "Smith", Username: "JohnSmith", Avatar: null, Colors: [colors[0], colors[1]]}
return (
<div className={styles.navProvider}>
<div className={styles.nav} style={{width: navState? "300px" : "0px"}}>
<div className={styles.navContent}>
<div className={styles.navAvatar}>
<Avatar User={user} ShowInitial/>
</div>
<div className={styles.userInfo}>
<p className={styles.name}>{user.FirstName} {user.LastName}</p>
<p className={styles.username}>{`@${user.Username}`}</p>
<p className={styles.friends}><span className={styles.friendsValue}>{`283`}</span> Friends</p>
</div>
<div className={styles.menuItems}>
<NavMenuItem label="Profile" icon={<AiOutlineUser size={20}/>}/>
</div>
</div>
</div>
<div className={styles.content}>
{children}
</div>
</div>
)
}
export default NavigationProvider;
\ No newline at end of file
import { FC, PropsWithChildren } from "react";
import styles from "../../styles/HiddenPost.module.css"
import { BsEyeSlash } from 'react-icons/bs';
import Avatar from "../profile/avatar";
import { User } from "@/types/user";
type HiddenPostProps ={
User: User;
TimeStamp: string;
}
const HiddenPost: FC<PropsWithChildren<HiddenPostProps>> = ({
User,
TimeStamp
}) => {
return (
<div className={styles.hiddenPost}>
<div className={styles.hiddenHeader}>
<Avatar User={User} ShowInitial={false}/>
<div className={styles.timestamp}>
{TimeStamp}
</div>
</div>
<div className={styles.hiddenCard}>
<div className={styles.hiddenCardContent}>
<BsEyeSlash size={30}/>
<p className={styles.title}>Post Hidden</p>
<p className={styles.text}>Post a thought to view</p>
</div>
</div>
</div>
)
}
export default HiddenPost;
import { User } from "@/types/user";
import { FC, PropsWithChildren } from "react";
import styles from '../../styles/Post.module.css'
import PostAction from "./PostAction";
import { generateRandomLinearGradient } from "./Utils";
import { SlBubble, SlShare } from 'react-icons/sl'
import { AiOutlineHeart } from 'react-icons/ai'
import Avatar from "../profile/avatar";
type PostProps = {
User: User,
Post: string,
TimeStamp?: string,
Likes: User[],
}
const Post: FC<PropsWithChildren<PostProps>> = ({
User,
Post,
TimeStamp,
Likes
}) => {
return (
<div className={styles.post}>
<div className={styles.header}>
<Avatar User={User} ShowInitial/>
<div className={styles.headerInfo}>
<div className={styles.headerUserInfo}>
<p className={styles.name} >{User.FirstName} {User.LastName}</p>
<p className={styles.username}>@{User.Username}</p>
</div>
<div className={styles.timestamp}>
{TimeStamp}
</div>
</div>
</div>
<div className={styles.postContentContainer}>
<p className={styles.postContent}>{Post}</p>
<div className={styles.postActions}>
<PostAction label="7" icon={<SlBubble />} onClick={null}/>
<PostAction label="0" icon={<AiOutlineHeart />} />
<PostAction icon={<SlShare />}/>
</div>
</div>
</div>
)
}
export default Post;
\ No newline at end of file
import { FC, PropsWithChildren } from 'react'
import styles from '../../styles/PostAction.module.css'
type PostActionProps ={
label?: string;
icon: any
onClick: () => any;
}
const PostAction: FC<PropsWithChildren<PostActionProps>> = ({
label,
icon,
onClick
}) => {
return (
<div className={styles.container}>
<button className={styles.button} onClick={onClick}>
{icon}
{label &&
<span className={styles.label}>{label}</span>
}
</button>
</div>
)
}
export default PostAction;
\ No newline at end of file
export function generateRandomLinearGradient(colors: string[], fixedAngle: boolean): string{
const randomAngle = 117;
const gradient = 20;
return `linear-gradient(${fixedAngle? 117 : randomAngle}deg, ${colors[0]} ${gradient}%, ${colors[1]} ${100-gradient}%)`
}
\ No newline at end of file
import { User } from '@/types/user';
import { FC, PropsWithChildren } from 'react';
import styles from '../../styles/Avatar.module.css'
import { generateRandomLinearGradient } from '../post/Utils';
type AvatarProps ={
User: User
ShowInitial?: boolean
}
const Avatar:FC<PropsWithChildren<AvatarProps>> = ({
User,
ShowInitial = false
}) => {
return (
<div className={styles.avatar} style={{backgroundImage: generateRandomLinearGradient(User.Colors, true)}}>
{User.Avatar &&
<div>
</div>
}
{!User.Avatar && ShowInitial &&
<div>
<p>{User.Username[0]}</p>
</div>
}
</div>
)
}
export default Avatar;
\ No newline at end of file
import styles from '../../styles/TitleBar.module.css'
import { RxHamburgerMenu } from "react-icons/rx"
import { FC, PropsWithChildren, useState } from 'react';
type TitleBarProps = {
NavBarToggle: () => void;
}
const TitleBar:FC<PropsWithChildren<TitleBarProps>> = ({
NavBarToggle
}) => {
return (
<div className={styles.titlebar}>
<button className={styles.navButton} onClick={() => NavBarToggle()}><RxHamburgerMenu size={"32px"}/></button>
<p className={styles.title}>Feed</p>
<button>Settings</button>
</div>
)
}
export default TitleBar;
\ No newline at end of file
import HiddenPost from "@/components/post/HiddenPost";
import Post from "@/components/post/Post";
const Feed = () => {
let colors = ["#ffd0d2","#fffdd0","#d0fffd","#d0d2ff"];
let user = {FirstName: "John", LastName: "Smith", Username: "JohnSmith", Avatar: null, Colors: [colors[0], colors[1]]}
return (
<div>
<Post
User={user}
Likes={[]}
Post="This is my amazing post"
TimeStamp='Just now'
/>
<HiddenPost User={user} TimeStamp="Just now"/>
</div>
)
}
export default Feed;
\ No newline at end of file
import Head from 'next/head'
import Image from 'next/image'
import { Inter } from 'next/font/google'
import Test from './test'
import styles from '../styles/Home.module.css'
import NavigationProvider from '@/components/navigation/NavProvider'
import { useState } from 'react'
import TitleBar from '@/components/titlebar/TitleBar'
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
const [navState, setNavState] = useState<boolean>(false);
return (
<>
<Head>
......@@ -15,8 +22,11 @@ export default function Home() {
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<Test />
<main className={styles.home}>
<NavigationProvider navState={navState}>
<TitleBar NavBarToggle={() => setNavState(!navState)}/>
</NavigationProvider>
</main>
</>
)
......
const Test = () => {
return(
<div>
testX
</div>
)
}
export default Test;
\ No newline at end of file
.avatar {
color: white;
border-radius: 50%;
width: 56px;
height: 56px;
background-color: 'red';
display: flex;
justify-content: center;
align-items: center;
}
\ No newline at end of file
.hiddenPost {
border-radius: 24px;
margin: 30px;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
/* background: rgba(0, 0, 0, 0.13); */
padding: 16px 8px;
}
.hiddenHeader {
height: 56px;
display: flex;
justify-content: space-between;
align-items: center;
}
.hiddenCard {
border-radius: 24px;
height: 150px;
max-height: 300px;
display: flex;
justify-content: center;
align-items: center;
margin: 8px 0px 0px 24px;
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
overflow: hidden;
}
.hiddenCardContent{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
white-space: nowrap;
}
.title {
font-weight: bold;
font-size: 1rem;
}
.text{
font-size: 0.75rem;
}
.timestamp{
font-size: small;
display: flex;
align-items: flex-end;
height: 100%;
justify-content: end;
color:rgb(100 116 139);
}
\ No newline at end of file
.home{
}
\ No newline at end of file
.menuItem {
margin: 8px 0px;;
padding: 16px 24px;
/* color:rgb(100 116 139); */
border-radius: 32px;
border: 1px solid rgb(226 232 240);
white-space: nowrap;
display: flex;
align-items: center;
}
.label {
margin-left: 8px;
}
\ No newline at end of file
.navProvider {
display: flex;
height: 100vh;
box-sizing: border-box;
}
.nav {
transition: 0.2s;
border-radius: 24px;
box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px;
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
}
.navContent {
margin: 24px;
margin-top: 48px;
}
.navAvatar{
display: flex;
width: 100%;
margin-bottom: 8px;
}
.userInfo {
margin-bottom: 16px;
}
.name {
font-weight: light;
white-space: nowrap;
margin-bottom: 4px;
font-weight: bolder;
}
.username {
font-size: smaller;
white-space: nowrap;
color:rgb(100 116 139);
margin-bottom: 8px;
}
.friends {
white-space: nowrap;
font-size: smaller;
color:rgb(100 116 139);
}
.friendsValue {
color: black;
font-weight: bold;
}
.content {
flex-grow: 1;
}
.menuItems{
padding-top: 8px;
border-top:1px solid rgb(226 232 240)
}
\ No newline at end of file
.post {
/* border: 1px solid black;
border-radius: 15px; */
display: flex;
flex-direction: column;
margin: 30px;
padding: 16px 8px;
}
.header {
display: flex;
width: 100%;
flex-direction: row;
align-items: center;
margin-bottom: 8px;
height: 56px;
}
.headerInfo {
height: 100%;
display: flex;
flex-grow: 1;
align-items: center;
margin-left: 8px;
}
.headerUserInfo {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.name {
font-weight: bold;
}
.username {
height: 100%;
font-size: small;
}
.timestamp{
font-size: small;
display: flex;
align-items: flex-end;
height: 100%;
justify-content: end;
color:rgb(100 116 139);
}
.postContentContainer {
padding: 12px 16px;
border-radius: 24px;
box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
margin: 0px 0px 0px 24px;
}
.postContent {
padding: 8px;
padding-bottom: 4px;
font-size: large;
}
.postActions {
padding: 0px 8px;
padding-top: 4px;
display: flex;
width: 100%;
max-width: 200px;
justify-content: space-between;
}
\ No newline at end of file
.container {
color: rgb(203 213 225);
margin-right: 8px;
display: flex;
justify-content: center;
border-radius: 8px;
padding: 4px;
padding-left: 8px;;
}
.container:hover {
background-color: rgb(226 232 240);
}
.button {
display: flex;
justify-content: center;
align-items: center;
font-size: medium;
background: none;
border: none;
color:rgb(100 116 139);
}
.label {
margin: 4px;
}
\ No newline at end of file