Styling and structure of main recipes page.

This commit is contained in:
Jesse Brault 2024-08-01 10:11:55 -05:00
parent 159f0177eb
commit a983d49f22
12 changed files with 199 additions and 69 deletions

View File

@ -0,0 +1,11 @@
import './footer.module.css'
const Footer = () => {
return (
<footer>
<p>Copyright 2024 Jesse R. Brault. All rights reserved.</p>
</footer>
)
}
export default Footer

View File

@ -0,0 +1,3 @@
footer {
padding: 20px;
}

View File

@ -0,0 +1,27 @@
import { useNavigate, useRouter } from '@tanstack/react-router'
import { useAuth } from '../../auth'
import classes from './header.module.css'
const Header = () => {
const auth = useAuth()
const router = useRouter()
const navigate = useNavigate()
const onLogout = async () => {
auth.clearToken(async () => {
await router.invalidate()
await navigate({ to: '/login' })
})
}
return (
<header>
<h1 className={classes.mealsMadeEasy}>Meals Made Easy</h1>
<nav>
<button onClick={onLogout}>Logout</button>
</nav>
</header>
)
}
export default Header

View File

@ -0,0 +1,11 @@
header {
display: flex;
align-items: center;
justify-content: space-between;
background-color: var(--primary-red);
padding: 20px;
}
.meals-made-easy {
color: var(--primary-white);
}

View File

@ -38,28 +38,40 @@ const RecipeCard = ({
/>
</Link>
<div className={classes.infoContainer}>
<Link
to="/recipes/$username/$slug"
params={{
username: ownerUsername,
slug
}}
>
<h1 className={classes.title}>{title}</h1>
</Link>
<span>
<FontAwesomeIcon icon="star" size="sm" />
{starCount}
</span>
<span>
<FontAwesomeIcon icon="user" />
{ownerUsername}
</span>
{isPublic ? (
<FontAwesomeIcon icon="globe" size="sm" />
) : (
<FontAwesomeIcon icon="lock" size="sm" />
)}
<div className={classes.infoRow}>
<Link
className={classes.titleLink}
to="/recipes/$username/$slug"
params={{
username: ownerUsername,
slug
}}
>
<h1 className={classes.title}>{title}</h1>
</Link>
<span className={classes.starInfo}>
<FontAwesomeIcon
icon="star"
className={classes.star}
size="sm"
/>
{starCount}
</span>
</div>
<div className={classes.infoRow}>
<span className={classes.userInfo}>
<FontAwesomeIcon
icon="user"
className={classes.userIcon}
/>
{ownerUsername}
</span>
{isPublic ? (
<FontAwesomeIcon icon="globe" size="sm" />
) : (
<FontAwesomeIcon icon="lock" size="sm" />
)}
</div>
</div>
</article>
)

View File

@ -1,18 +1,44 @@
.recipe-card {
max-width: 400px;
border: 1px solid black;
justify-self: stretch;
}
.recipe-image {
max-width: 100%;
width: 100%;
max-height: 200px;
object-fit: cover;
}
.info-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
align-items: baseline;
display: flex;
flex-direction: column;
row-gap: 10px;
}
.info-row {
display: flex;
justify-content: space-between;
}
.title {
margin-block: 0;
font-size: 18px;
}
.star-info {
display: flex;
column-gap: 5px;
align-items: center;
}
.star {
color: var(--primary-yellow);
}
.user-info {
display: flex;
column-gap: 5px;
}
.user-icon {
color: var(--primary-red);
}

24
src/main.css Normal file
View File

@ -0,0 +1,24 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
:root {
--primary-white: #ffffff;
--primary-red: #91351d;
--primary-yellow: #ffb61d;
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
}
a {
color: var(--primary-red);
}
a:visited {
color: var(--primary-red);
}
a:hover {
color: hsl(from var(--primary-red) h s l / 0.9);
}

View File

@ -6,6 +6,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { AuthProvider, useAuth } from './auth'
import { library } from '@fortawesome/fontawesome-svg-core'
import { fas } from '@fortawesome/free-solid-svg-icons'
import './main.css'
// Font-Awesome: load icons
library.add(fas)

View File

@ -4,6 +4,7 @@ import { useState } from 'react'
import { useAuth } from '../../auth'
import { ApiError } from '../../api/ApiError'
import RecipeCard from '../../components/recipe-card/RecipeCard'
import classes from './recipes.module.css'
const Recipes = () => {
const [pageNumber, setPageNumber] = useState(0)
@ -35,20 +36,29 @@ const Recipes = () => {
return <p>Error: {error.message}</p>
}
} else {
return data.content.map(view => (
<RecipeCard
key={view.id}
title={view.title}
ownerUsername={view.ownerUsername}
slug={view.slug}
mainImageUrl={view.mainImage.url}
mainImageAlt={
view.mainImage.alt ? view.mainImage.alt : undefined
}
starCount={view.starCount}
isPublic={view.isPublic}
/>
))
return (
<>
<h1>Recipes</h1>
<section className={classes.recipeList}>
{data.content.map(view => (
<RecipeCard
key={view.id}
title={view.title}
ownerUsername={view.ownerUsername}
slug={view.slug}
mainImageUrl={view.mainImage.url}
mainImageAlt={
view.mainImage.alt
? view.mainImage.alt
: undefined
}
starCount={view.starCount}
isPublic={view.isPublic}
/>
))}
</section>
</>
)
}
}

View File

@ -0,0 +1,23 @@
.recipe-list {
display: grid;
justify-content: space-evenly;
gap: 20px;
}
@media screen and (min-width: 900px) {
.recipe-list {
grid-template-columns: repeat(2, 1fr);
}
}
@media screen and (min-width: 1300px) {
.recipe-list {
grid-template-columns: repeat(3, 1fr);
}
}
@media screen and (min-width: 1700px) {
.recipe-list {
grid-template-columns: repeat(4, 1fr);
}
}

View File

@ -0,0 +1,3 @@
main {
padding: 20px;
}

View File

@ -1,39 +1,18 @@
import {
Outlet,
createRootRouteWithContext,
useNavigate,
useRouter
} from '@tanstack/react-router'
import { Outlet, createRootRouteWithContext } from '@tanstack/react-router'
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
import RouterContext from '../RouterContext'
import { useAuth } from '../auth'
import Header from '../components/header/Header'
import Footer from '../components/footer/Footer'
import './__root.module.css'
const RootLayout = () => {
const auth = useAuth()
const router = useRouter()
const navigate = useNavigate()
const onLogout = async () => {
auth.clearToken(async () => {
await router.invalidate()
await navigate({ to: '/login' })
})
}
return (
<>
<header>
<h1>Meals Made Easy</h1>
<nav>
<button onClick={onLogout}>Logout</button>
</nav>
</header>
<Header />
<main>
<Outlet />
</main>
<footer>
<p>Copyright 2024 Jesse R. Brault. All rights reserved.</p>
</footer>
<Footer />
<TanStackRouterDevtools position="bottom-right" />
</>
)