UI update

This commit is contained in:
2026-03-07 06:29:00 +00:00
parent 27f7d11fca
commit 5922d6ca31
6 changed files with 132 additions and 37 deletions

View File

@@ -1,5 +1,54 @@
<template> <template>
<v-app class="recipe-bg"> <v-app class="recipe-bg">
<v-app-bar
color="transparent"
flat
elevation="0"
class="px-4"
height="70"
>
<v-app-bar-title
class="nav-brand"
style="cursor: pointer; user-select: none;"
@click="navigateTo('/')"
>
Seasoned
</v-app-bar-title>
<v-spacer></v-spacer>
<div class="nav-links d-flex align-center">
<v-btn
to="/gallery"
class="nav-auth-btn ml-4"
variant="outlined"
elevation="0"
>
Collection
</v-btn>
<v-btn
v-if="!token"
to="/login"
class="nav-auth-btn ml-4"
variant="outlined"
elevation="0"
>
Sign In
</v-btn>
<v-btn
v-else
@click="logout"
class="nav-auth-btn ml-4"
variant="outlined"
elevation="0"
>
Logout
</v-btn>
</div>
</v-app-bar>
<v-main> <v-main>
<NuxtPage /> <NuxtPage />
</v-main> </v-main>
@@ -8,4 +57,16 @@
<script setup> <script setup>
import '@/assets/css/app-theme.css' import '@/assets/css/app-theme.css'
const token = useCookie('seasoned_token')
const logout = () => {
token.value = null
if (import.meta.client) {
localStorage.removeItem('token')
}
navigateTo('/login')
}
</script> </script>

View File

@@ -1,21 +1,15 @@
@import url('https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=Inter:wght@400;600&display=swap');
.recipe-bg { .recipe-bg {
/* A rich, warm medium-brown walnut tone */
background-color: #5d4a36 !important; background-color: #5d4a36 !important;
/* Using the wood pattern but allowing the lighter base to show through */
background-image: url("https://www.transparenttextures.com/patterns/tileable-wood-colored.png") !important; background-image: url("https://www.transparenttextures.com/patterns/tileable-wood-colored.png") !important;
background-size: 500px; /* Slightly larger scale makes the grain easier to see */ background-size: 500px;
background-attachment: fixed; background-attachment: fixed;
} }
/* Ensure the card has a natural 'sit' on this visible wood */
.recipe-card { .recipe-card {
background-color: #f4e4bc !important; background-color: #f4e4bc !important;
background-image: url("https://www.transparenttextures.com/patterns/natural-paper.png"); background-image: url("https://www.transparenttextures.com/patterns/natural-paper.png");
border: 1px solid #c9b996 !important; border: 1px solid #c9b996 !important;
border-radius: 12px !important; border-radius: 12px !important;
/* A deeper, more spread-out shadow to account for the lighter background */
box-shadow: 0 15px 45px rgba(0, 0, 0, 0.35) !important; box-shadow: 0 15px 45px rgba(0, 0, 0, 0.35) !important;
} }
@@ -29,9 +23,8 @@
.brand-subtitle { .brand-subtitle {
font-family: 'Libre Baskerville', serif; font-family: 'Libre Baskerville', serif;
font-style: italic;
color: #6d5e4a; color: #6d5e4a;
font-size: 0.85rem; font-size: 1.1rem;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 3px; letter-spacing: 3px;
} }
@@ -116,7 +109,6 @@
text-align: center !important; text-align: center !important;
} }
/* 2. Center the floating label specifically */
.custom-input .v-label.v-field-label { .custom-input .v-label.v-field-label {
left: 50% !important; left: 50% !important;
transform: translateX(-50%) !important; transform: translateX(-50%) !important;
@@ -124,7 +116,6 @@
justify-content: center !important; justify-content: center !important;
} }
/* 3. Ensure both elements are the exact same height and shape */
.custom-input .v-field { .custom-input .v-field {
height: 56px !important; height: 56px !important;
min-height: 56px !important; min-height: 56px !important;
@@ -134,12 +125,10 @@
justify-content: center !important; justify-content: center !important;
} }
/* 4. Remove the prepend icon space that kicks text to the right */
.custom-input .v-field__prepend-inner { .custom-input .v-field__prepend-inner {
display: none !important; display: none !important;
} }
/* 5. Typography match: ensure font weight and size are identical */
.custom-input .v-label { .custom-input .v-label {
font-family: 'Inter', sans-serif !important; font-family: 'Inter', sans-serif !important;
font-weight: 600 !important; font-weight: 600 !important;
@@ -147,7 +136,6 @@
letter-spacing: normal !important; letter-spacing: normal !important;
} }
/* Drag and Drop Zone Styling */
.drop-zone { .drop-zone {
width: 100%; width: 100%;
height: 150px; height: 150px;
@@ -222,4 +210,44 @@
.d-flex .analyze-btn { .d-flex .analyze-btn {
margin-bottom: 0 !important; margin-bottom: 0 !important;
}
.v-app-bar {
background: linear-gradient(to bottom, rgba(0,0,0,0.4) 0%, transparent 100%) !important;
}
.nav-brand {
font-family: 'Libre Baskerville', serif !important;
color: #f4e4bc !important;
text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.8) !important;
font-size: 1.8rem !important;
letter-spacing: 1px;
}
.nav-auth-btn, .nav-btn {
font-family: 'Libre Baskerville', serif !important;
font-size: 1.3rem !important;
color: #f4e4bc !important;
border: 1.5px solid rgba(244, 228, 188, 0.6) !important;
background-color: rgba(0, 0, 0, 0.2) !important;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8) !important;
letter-spacing: 1px;
}
.nav-auth-btn:hover, .nav-btn:hover {
background-color: #f4e4bc !important;
color: #2e1e0a !important;
text-shadow: none !important;
}
.brand-icon-container {
/* Subtle rustic touch */
filter: sepia(0.2) contrast(1.1);
opacity: 0.9;
}
.brand-icon-container .v-img {
/* Gives it a slightly 'stamped' look on the paper */
filter: drop-shadow(0px 1px 1px rgba(0,0,0,0.1));
} }

View File

@@ -35,8 +35,8 @@
} }
.back-to-home-btn { .back-to-home-btn {
background-color: #5d4037 !important; /* Rich walnut brown */ background-color: #5d4037 !important;
color: #f8f1e0 !important; /* Parchment text */ color: #f8f1e0 !important;
font-family: 'Libre Baskerville', serif !important; font-family: 'Libre Baskerville', serif !important;
text-transform: none !important; text-transform: none !important;
font-size: 1.1rem !important; font-size: 1.1rem !important;

View File

@@ -1,7 +1,4 @@
/* app/assets/css/auth.css */
.auth-card { .auth-card {
/* Inherits recipe-card but adds a tighter feel for a login form */
max-width: 450px; max-width: 450px;
margin-top: 5vh; margin-top: 5vh;
} }
@@ -14,7 +11,6 @@
margin-bottom: 8px; margin-bottom: 8px;
} }
/* Enhancing the custom-input for Auth with icons */
.auth-input .v-field__prepend-inner { .auth-input .v-field__prepend-inner {
display: flex !important; display: flex !important;
padding-right: 12px; padding-right: 12px;
@@ -38,7 +34,6 @@
color: #2e1e0a !important; color: #2e1e0a !important;
} }
/* Subtle animation when switching between Login and Register */
.auth-switch-enter-active, .auth-switch-leave-active { .auth-switch-enter-active, .auth-switch-leave-active {
transition: all 0.3s ease; transition: all 0.3s ease;
} }

View File

@@ -30,26 +30,30 @@
<v-row v-else-if="recipes?.length"> <v-row v-else-if="recipes?.length">
<v-col v-for="recipe in recipes" :key="recipe.id" cols="12" sm="6" md="4"> <v-col v-for="recipe in recipes" :key="recipe.id" cols="12" sm="6" md="4">
<v-card class="gallery-item-card pa-4"> <v-card class="gallery-item-card pa-4">
<v-img <v-sheet
src="https://images.unsplash.com/photo-1546069901-ba9599a7e63c"
height="200" height="200"
cover color="#f8f5f0"
class="rounded-sm mb-4 recipe-thumbnail" class="rounded-sm mb-4 d-flex align-center justify-center"
style="border: 1px solid #e8e2d6;"
> >
<template v-slot:placeholder> <v-icon
<v-row class="fill-height ma-0" align="center" justify="center"> :icon="getRecipeIcon(recipe.title)"
<v-progress-circular indeterminate color="#556b2f"></v-progress-circular> size="80"
</v-row> color="#d1c7b7"
</template> ></v-icon>
</v-img> </v-sheet>
<h3 class="gallery-item-title text-center">{{ recipe.title }}</h3> <h3 class="gallery-item-title text-center">{{ recipe.title }}</h3>
<p class="gallery-item-date text-center"> <p class="gallery-item-date text-center">
Added {{ new Date(recipe.createdAt).toLocaleDateString('en-US', { month: 'long', year: 'numeric' }) }} Added {{ new Date(recipe.createdAt).toLocaleDateString('en-US', { month: 'long', year: 'numeric' }) }}
</p> </p>
<v-card-actions class="justify-center"> <v-card-actions class="justify-center">
<v-btn variant="text" class="view-recipe-btn" color="#556b2f"> <v-btn
variant="text"
class="view-recipe-btn"
color="#556b2f"
@click="openRecipe(recipe)"
>
Open Recipe Open Recipe
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
@@ -74,24 +78,23 @@ import '@/assets/css/gallery.css'
const config = useRuntimeConfig() const config = useRuntimeConfig()
const recipes = ref([]) const recipes = ref([])
const loading = ref(true) const loading = ref(true)
const showDetails = ref(false)
const selectedRecipe = ref(null)
onMounted(async () => { onMounted(async () => {
await fetchRecipes() await fetchRecipes()
}) })
const fetchRecipes = async () => { const fetchRecipes = async () => {
// Get the token we saved during login
const token = useCookie('seasoned_token').value const token = useCookie('seasoned_token').value
|| (import.meta.client ? localStorage.getItem('token') : null) || (import.meta.client ? localStorage.getItem('token') : null)
if (!token) { if (!token) {
// If no token, kick them back to login
return navigateTo('/login') return navigateTo('/login')
} }
try { try {
loading.value = true loading.value = true
// You'll need to add this GET endpoint to your RecipeController
const data = await $fetch(`${config.public.apiBase}api/recipe/my-collection`, { const data = await $fetch(`${config.public.apiBase}api/recipe/my-collection`, {
headers: { headers: {
'Authorization': `Bearer ${token}` 'Authorization': `Bearer ${token}`

View File

@@ -3,7 +3,15 @@
<v-card class="recipe-card pa-10 mx-auto mt-10" max-width="950" elevation="1"> <v-card class="recipe-card pa-10 mx-auto mt-10" max-width="950" elevation="1">
<header class="text-center mb-10"> <header class="text-center mb-10">
<h1 class="brand-title">Seasoned</h1> <div class="brand-icon-container mb-4">
<v-img
alt="Seasoned Logo"
width="120"
class="mx-auto"
cover
></v-img>
</div>
<p class="brand-subtitle">A Recipe Collection</p> <p class="brand-subtitle">A Recipe Collection</p>
</header> </header>