view recipe display

This commit is contained in:
kaipher7
2026-04-22 02:31:29 -06:00
parent 2499ea086d
commit 725244a6d7
3 changed files with 282 additions and 181 deletions
+1 -1
View File
@@ -246,7 +246,7 @@ body, html {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-family: 'Delius Swash Caps', cursive;;
font-family: 'Mali', cursive;;
font-weight: 400;
}
+215 -103
View File
@@ -31,7 +31,7 @@ body, html {
font-family: 'Mali', cursive;
background-color: var(--pale-yellow);
overflow-x: hidden;
overflow-y: auto;
overflow-y: hidden;
}
/* =========================
@@ -43,10 +43,11 @@ body, html {
height: 100%;
}
.body-left, .body-right {
.body-left {
position: sticky;
flex-grow: 0;
width: 400px;
flex-shrink: 0;
width: 250px;
}
/* =========================
@@ -88,7 +89,7 @@ body, html {
background-color: var(--peach);
color: var(--dark);
padding: 6px;
font-size: 1.75em;
font-size: 1.8em;
font-weight: 900;
letter-spacing: 1.5px;
display: flex;
@@ -121,7 +122,7 @@ body, html {
border: none;
padding: 0;
cursor: pointer;
height: 100px;
height: 85px;
width: auto;
border-radius: 8px;
transition: transform 0.2s ease;
@@ -131,6 +132,8 @@ body, html {
transform: scale(1.05);
}
/* =========================
Floating Create Icon
========================= */
@@ -142,6 +145,28 @@ body, html {
transition: transform 0.2s ease;
}
.create_icon::after {
content: "Create a recipe";
display: none;
position: absolute;
left: 50%;
bottom: 100%;
transform: translateX(-50%);
background: var(--dark-yellow);
color: var(--dusty-red);
font-family: 'Mali', cursive;
font-size: 0.85em;
font-weight: 600;
white-space: nowrap;
padding: 4px 10px;
border-radius: 10px;
}
.create_icon:hover::after {
display: block;
}
.create_icon:hover {
transform: scale(1.02);
}
@@ -152,40 +177,6 @@ body, html {
border-radius: 10%;
}
/* =========================
Right Sidebar
========================= */
.sidebar-right {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
margin: 25px;
padding: 5px;
height: 75%;
border-radius: 20px;
z-index: 10;
background-color: var(--peach);
color: var(--dusty-red);
font-size: 1.6em;
font-weight: 900;
letter-spacing: 1.5px;
}
.sidebar-right ul {
list-style: none;
padding: 0;
}
.sidebar-right li {
margin-bottom: 5px;
}
.sidebar-right a {
color: var(--dusty-red);
text-decoration: none;
}
/* =========================
Main Content Area
========================= */
@@ -195,82 +186,203 @@ body, html {
display: flex;
justify-content: center;
align-items: flex-start;
overflow: scroll;
height: 100%;
overflow-y: auto;
scrollbar-color: var(--dusty-red) transparent;
}
/* =========================
Recipe Cards Layout
Recipe Container
========================= */
.recipe-card {
margin-top: 35px;
.recipe-container {
width: 100%;
max-width: 1100px;
margin: 35px auto;
display: flex;
flex-direction: column;
justify-content: center;
}
.recipe-section {
border-radius: 20px;
padding: 18px 24px;
color: var(--dark);
display: flex;
flex-direction: row;
gap: 28px;
margin-bottom: 30px;
font-size: 1.05em;
}
.recipe-section h1 {
margin-top: 0;
font-size: 2.8em;
}
.recipe-section h2 {
margin-top: 0;
}
.left-view, .right-view {
flex: 1;
max-width: 500px;
}
/* Author */
.recipe-author {
font-size: 1.4em;
margin-bottom: 20px;
color: var(--dusty-red);
}
.recipe-author a{
font-size: 1.1em;
font-weight: 600;
color: var(--dusty-red);
transition: background-color 0.1s ease;
}
.recipe-author a:hover{
color: var(--dusty-red-hover);
}
/* Image */
.recipe-image-wrap {
margin-bottom: 36px;
}
.recipe-image-wrap img {
display: block;
width: 100%;
max-width: 700px;
max-height: 420px;
object-fit: cover;
border-radius: 16px;
margin: 0 auto;
}
.recipe-no-image {
margin-bottom: 28px;
font-style: italic;
}
/* Description */
.recipe-description {
margin-bottom: 25px;
font-weight: 500;
}
/* Meta row — prep, cook, servings, cost */
.recipe-meta {
display: flex;
flex-direction: column;
gap: 20px;
margin-bottom: 30px;
font-size: 1.4em;
}
.recipe-meta p {
margin: 0;
color: var(--dusty-red);
font-weight: 500;
}
.recipe-meta strong {
margin: 0;
color: var(--dark);
}
/* Ingredients */
.recipe-ingredients {
margin-bottom: 30px;
background: var(--dark-yellow);
border-radius: 12px;
padding: 16px;
}
.recipe-ingredients ul {
line-height: 1.8;
}
/* Steps */
.recipe-steps {
font-weight: 500;
margin-bottom: 30px;
}
.recipe-steps ol {
line-height: 1.9;
}
/* Tags */
.recipe-tags {
margin-bottom: 25px;
background: var(--dark-yellow);
border-radius: 12px;
padding: 16px;
color: var(--dusty-red);
}
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 35px;
justify-content: flex-start;
flex-direction: row;
height: fit-content;
}
a {
text-decoration: none;
color: var(--dark);
}
/* =========================
Individual Card (Folder Style)
========================= */
.card {
position: relative; /* needed for tab */
display: flex;
align-items: center;
gap: 10px;
flex: 1 1 260px;
max-width: 400px;
max-height: 200px;
padding: 25px 20px 20px; /* extra space for tab */
border-radius: 12px;
background: var(--peach);
}
/* Folder Tab */
.card::before {
content: "";
position: absolute;
top: -16px;
left: 0px;
width: 100px;
height: 28px;
background: var(--peach);
border-radius: 6px 6px 0 0;
.tag-list span {
background: var(--pale-yellow);
padding: 8px 14px;
border-radius: 999px;
font-weight: 700;
}
/* =========================
Card Content
========================= */
.card .card-text {
height: 100%;
overflow: hidden; /* the scroll bars were difficult to look at, the user can just view the recipe*/
font-family: 'Roboto', sans-serif;
/* Bottom links */
.recipe-links {
display: flex;
gap: 20px;
flex-wrap: wrap;
margin-top: 25px;
}
.recipe-links a {
color: var(--dusty-red);
}
.save-btn {
background: var(--dusty-red);
color: var(--dark-yellow);
border: none;
border-radius: 10px;
padding: 8px 18px;
margin-bottom: 60px;
font-family: 'Mali', cursive;
font-size: 1.4em;
width: 40%;
font-weight: 700;
cursor: pointer;
transition: background 0.1s ease;
align-self: center;
}
.save-btn:hover {
background: var(--dusty-red-hover);
}
.save-btn.saved {
background: var(--dark);
color: var(--pale-yellow);
}
/* Not found */
.recipe-not-found {
width: 100%;
max-width: 950px;
margin: 35px auto;
}
.recipe-not-found section {
background: var(--peach);
border-radius: 20px;
padding: 28px 32px;
color: var(--dark);
}
/* =========================
Card Image
========================= */
.card img {
width: 100%;
height: 100px;
object-fit: cover;
border-radius: 8px;
}
/* =========================
Card Columns
========================= */
.card-left,
.card-right {
flex-shrink: 0;
width: 50%;
}
+41 -52
View File
@@ -39,45 +39,25 @@
<!-- Main Content -->
<main class="main-content">
<div th:if="${recipe != null}" style="width: 100%; max-width: 950px; margin: 35px auto;">
<div th:if="${recipe != null}" class="recipe-container">
<section class="recipe-section">
<div class="left-view">
<h1 th:text="${recipe.title}">Recipe Title</h1>
<section style="background: var(--peach); border-radius: 20px; padding: 18px 24px; color: var(--dark);">
<h1 style="margin-top: 0; font-size: 2.8em;" th:text="${recipe.title}">Recipe Title</h1>
<p th:if="${recipe.userDto != null}" style="font-size: 1.2em; margin-bottom: 20px;">
<p th:if="${recipe.userDto != null}" class="recipe-author">
<strong>Author:</strong>
<a th:href="@{/users/{id}(id=${recipe.userDto.id})}"
th:text="${recipe.userDto.displayName != null and !#strings.isEmpty(recipe.userDto.displayName) ? recipe.userDto.displayName : recipe.userDto.username}">
Author Name
</a>
th:text="${recipe.userDto.effectiveDisplayName}">Author Name</a>
</p>
<div th:if="${recipe.images != null and !#lists.isEmpty(recipe.images)}" style="margin-bottom: 28px;">
<img th:src="${recipe.images[0].imageUrl}"
alt="Recipe Image"
style="display:block; width:100%; max-width:700px; max-height:420px; object-fit:cover; border-radius:16px; margin:0 auto;">
</div>
<p th:unless="${recipe.images != null and !#lists.isEmpty(recipe.images)}"
style="margin-bottom: 28px; font-style: italic;">
No image uploaded for this recipe.
</p>
<div style="margin-bottom: 25px;">
<div class="recipe-description">
<h2>Description</h2>
<p th:text="${recipe.description}">Recipe description</p>
</div>
<div style="display: flex; flex-wrap: wrap; gap: 20px; margin-bottom: 30px; font-size: 1.1em;">
<p><strong>Prep Time:</strong> <span th:text="${recipe.prepTimeMinutes}">0</span> minutes</p>
<p><strong>Cook Time:</strong> <span th:text="${recipe.cookTimeMinutes}">0</span> minutes</p>
<p><strong>Servings:</strong> <span th:text="${recipe.servings}">0</span></p>
<p><strong>Cost:</strong> <span th:text="${#strings.repeat('$', recipe.cost)}">$</span></p>
</div>
<div style="margin-bottom: 30px;">
<div class="recipe-ingredients">
<h2>Ingredients</h2>
<ul th:if="${recipe.ingredients != null and !#lists.isEmpty(recipe.ingredients)}" style="line-height: 1.8;">
<ul th:if="${recipe.ingredients != null and !#lists.isEmpty(recipe.ingredients)}">
<li th:each="ingredient : ${recipe.ingredients}">
<span th:text="${ingredient.quantity}">1</span>
<span th:text="${ingredient.unit}">cup</span>
@@ -89,49 +69,58 @@
<p th:unless="${recipe.ingredients != null and !#lists.isEmpty(recipe.ingredients)}">No ingredients listed.</p>
</div>
<div style="margin-bottom: 30px;">
<div class="recipe-steps">
<h2>Steps</h2>
<ol th:if="${recipe.steps != null and !#lists.isEmpty(recipe.steps)}" style="line-height: 1.9;">
<ol th:if="${recipe.steps != null and !#lists.isEmpty(recipe.steps)}">
<li th:each="step : ${recipe.steps}" th:text="${step.instruction}">Step instruction</li>
</ol>
<p th:unless="${recipe.steps != null and !#lists.isEmpty(recipe.steps)}">No steps listed.</p>
</div>
<div style="margin-bottom: 25px;">
<h2>Tags</h2>
<div th:if="${recipe.tags != null and !#lists.isEmpty(recipe.tags)}" style="display: flex; flex-wrap: wrap; gap: 10px;">
<span th:each="tag : ${recipe.tags}"
th:text="${tag.name}"
style="background: var(--pale-yellow); padding: 8px 14px; border-radius: 999px; font-weight: 700;">
Tag
</span>
</div>
<div class="right-view">
<div th:if="${recipe.images != null and !#lists.isEmpty(recipe.images)}" class="recipe-image-wrap">
<img th:src="${recipe.images[0].imageUrl}" alt="Recipe Image">
</div>
<p th:unless="${recipe.images != null and !#lists.isEmpty(recipe.images)}" class="recipe-no-image">
No image uploaded for this recipe.
</p>
<div class="recipe-meta">
<p><strong>Prep Time:</strong> <span th:text="${recipe.prepTimeMinutes}">0</span> minutes</p>
<p><strong>Cook Time:</strong> <span th:text="${recipe.cookTimeMinutes}">0</span> minutes</p>
<p><strong>Servings:</strong> <span th:text="${recipe.servings}">0</span></p>
<p><strong>Cost:</strong> <span th:text="${#strings.repeat('$', recipe.cost)}">$</span></p>
</div>
<div class="recipe-tags">
<h2>Tags: </h2>
<div th:if="${recipe.tags != null and !#lists.isEmpty(recipe.tags)}" class="tag-list">
<span th:each="tag : ${recipe.tags}" th:text="${tag.name}">Tag</span>
</div>
<p th:unless="${recipe.tags != null and !#lists.isEmpty(recipe.tags)}">No tags listed.</p>
</div>
<div style="display: flex; gap: 20px; flex-wrap: wrap; margin-top: 25px;">
<div class="recipe-links">
<a th:if="${recipe.userDto != null}"
th:href="@{/users/{id}(id=${recipe.userDto.id})}">
View author's profile
</a>
<a th:href="@{/explore}">Back to Explore</a>
th:href="@{/users/{id}(id=${recipe.userDto.id})}">View author's profile</a>
</div>
</section>
<button class="save-btn" th:data-recipe-id="${recipe.id}">Save Recipe</button>
</div>
<div th:unless="${recipe != null}" style="width: 100%; max-width: 950px; margin: 35px auto;">
<section style="background: var(--peach); border-radius: 20px; padding: 28px 32px; color: var(--dark);">
<div th:unless="${recipe != null}" class="recipe-not-found">
<section>
<h1>Recipe not found</h1>
<p><a th:href="@{/explore}">Back to Explore</a></p>
</section>
</div>
</main>
<!-- Right spacer/sidebar -->
<div class="body-right">
<div class="sidebar-right"></div>
</div>
</div>
</body>