UI update
This commit is contained in:
@@ -94,7 +94,7 @@ html, body {
|
|||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.drop-zone, .chat-container {
|
.drop-zone {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: rgba(62, 42, 20, 0.03) !important;
|
background-color: rgba(62, 42, 20, 0.03) !important;
|
||||||
border: 2px dashed #8c857b;
|
border: 2px dashed #8c857b;
|
||||||
@@ -133,7 +133,7 @@ html, body {
|
|||||||
text-transform: none !important;
|
text-transform: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-button {
|
.column-btn {
|
||||||
font-family: 'Libre Baskerville', serif !important;
|
font-family: 'Libre Baskerville', serif !important;
|
||||||
font-size: 1.1rem !important;
|
font-size: 1.1rem !important;
|
||||||
background-color: #556b2f !important;
|
background-color: #556b2f !important;
|
||||||
@@ -142,9 +142,8 @@ html, body {
|
|||||||
text-transform: none !important;
|
text-transform: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-button:hover {
|
.column-btn:hover {
|
||||||
background-color: #2e1e0a !important;
|
background-color: #2e1e0a !important;
|
||||||
|
|
||||||
text-shadow: none !important;
|
text-shadow: none !important;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
@@ -170,12 +169,6 @@ html, body {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-placeholder {
|
|
||||||
font-style: italic;
|
|
||||||
color: #8c7e6a;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-text {
|
.menu-text {
|
||||||
font-family: 'Libre Baskerville', serif !important;
|
font-family: 'Libre Baskerville', serif !important;
|
||||||
color: #2e1e0a !important;
|
color: #2e1e0a !important;
|
||||||
@@ -234,13 +227,13 @@ html, body {
|
|||||||
|
|
||||||
.chat-container {
|
.chat-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: rgba(244, 237, 225, 0.4) !important;
|
background-color: rgba(62, 42, 20, 0.03) !important;
|
||||||
border: 1px solid #dccca7;
|
border: 2px solid #8c857b;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 500px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-display {
|
.chat-display {
|
||||||
@@ -251,18 +244,98 @@ html, body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-display::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-display::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-display::-webkit-scrollbar-thumb {
|
||||||
|
background: #dccca7;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-display::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #8c7e6a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input .v-field__input {
|
.chat-input .v-field__input {
|
||||||
|
font-family: 'Libre Baskerville', serif !important;
|
||||||
|
font-size: 1.1rem;
|
||||||
min-height: 56px !important;
|
min-height: 56px !important;
|
||||||
padding-top: 15px !important;
|
padding-top: 15px !important;
|
||||||
font-family: 'Inter', sans-serif;
|
color: #2c2925 !important;
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input.v-field--focused {
|
.chat-container:focus-within {
|
||||||
background-color: #ffffff !important;
|
background-color: rgba(85, 107, 47, 0.05) !important;
|
||||||
transition: background-color 0.3s ease;
|
border-color: #556b2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-placeholder {
|
||||||
|
font-family: 'Libre Baskerville', serif !important;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
color: #8c7e6a;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-btn {
|
||||||
|
color: #2e1e0a !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
height: 36px !important;
|
||||||
|
width: 36px !important;
|
||||||
|
min-width: 36px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-btn:hover {
|
||||||
|
background-color: #556b2f !important;
|
||||||
|
color: #f4e4bc !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thinking-bubble {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 16px !important;
|
||||||
|
width: fit-content;
|
||||||
|
background-color: #ffffff; /* Same as assistant bubble */
|
||||||
|
border: 1px solid #dccca7;
|
||||||
|
border-radius: 15px 15px 15px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typing {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typing .dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background-color: #556b2f;
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 0.4;
|
||||||
|
animation: typing-bounce 1.4s infinite ease-in-out both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typing .dot:nth-child(1) { animation-delay: 0s; }
|
||||||
|
.typing .dot:nth-child(2) { animation-delay: 0.2s; }
|
||||||
|
.typing .dot:nth-child(3) { animation-delay: 0.4s; }
|
||||||
|
|
||||||
|
@keyframes typing-bounce {
|
||||||
|
0%, 80%, 100% { transform: scale(0); }
|
||||||
|
40% { transform: scale(1); opacity: 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
|
|||||||
@@ -4,17 +4,33 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.auth-title {
|
.auth-title {
|
||||||
font-family: 'Libre Baskerville', serif;
|
font-family: 'Libre Baskerville', serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 2.2rem;
|
font-size: 2.2rem;
|
||||||
color: #2e1e0a;
|
margin-top: -5px !important; /* Pulls the text up toward the pot */
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
line-height: 1.0 !important;
|
||||||
background: linear-gradient(to bottom, #8c4a32 20%, #4a2a14 100%);
|
background: linear-gradient(to bottom, #8c4a32 20%, #4a2a14 100%);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
line-height: 0.9 !important;
|
|
||||||
letter-spacing: -1px;
|
|
||||||
filter: drop-shadow(1px 1px 0px rgba(255,255,255,0.1));
|
filter: drop-shadow(1px 1px 0px rgba(255,255,255,0.1));
|
||||||
|
line-height: 1.1 !important;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-btn {
|
||||||
|
font-family: 'Libre Baskerville', serif !important;
|
||||||
|
font-size: 1.1rem !important;
|
||||||
|
background-color: #556b2f !important;
|
||||||
|
color: #f4e4bc !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
text-transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-btn:hover {
|
||||||
|
background-color: #2e1e0a !important;
|
||||||
|
text-shadow: none !important;
|
||||||
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-input .v-field__prepend-inner {
|
.auth-input .v-field__prepend-inner {
|
||||||
@@ -23,13 +39,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.auth-input .v-icon {
|
.auth-input .v-icon {
|
||||||
color: #f8f1e0 !important;
|
color: #2e1e0a !important;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-toggle-btn {
|
.auth-toggle-btn {
|
||||||
font-family: 'Inter', sans-serif !important;
|
font-family: 'Libre Baskerville', serif;
|
||||||
font-size: 0.85rem !important;
|
font-size: 1.0rem !important;
|
||||||
color: #6d5e4a !important;
|
color: #6d5e4a !important;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -43,7 +59,48 @@
|
|||||||
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-switch-enter-from, .auth-switch-leave-to {
|
.auth-switch-enter-from, .auth-switch-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(10px);
|
transform: translateY(10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-input :deep(.v-field) {
|
||||||
|
--v-theme-on-surface: 46, 30, 10 !important;
|
||||||
|
--v-field-label-color: 46, 30, 10 !important;
|
||||||
|
color: #2e1e0a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-input :deep(input),
|
||||||
|
.auth-input :deep(.v-field__input) {
|
||||||
|
font-family: 'Libre Baskerville', serif !important;
|
||||||
|
color: #2e1e0a !important;
|
||||||
|
-webkit-text-fill-color: #2e1e0a !important;
|
||||||
|
caret-color: #2e1e0a !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force the font on the floating label */
|
||||||
|
.auth-input :deep(.v-label) {
|
||||||
|
font-family: 'Libre Baskerville', serif !important;
|
||||||
|
color: #2e1e0a !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix for the white Success Message in your screenshot */
|
||||||
|
.auth-success {
|
||||||
|
background-color: rgba(85, 107, 47, 0.1) !important;
|
||||||
|
border-color: #556b2f !important;
|
||||||
|
color: #556b2f !important; /* Forces the green text */
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-success :deep(.v-icon) {
|
||||||
|
color: #556b2f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix for the Error Message */
|
||||||
|
.auth-error {
|
||||||
|
background-color: rgba(140, 74, 50, 0.1) !important;
|
||||||
|
border-color: #8c4a32 !important;
|
||||||
|
color: #8c4a32 !important;
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container>
|
<v-container>
|
||||||
<v-card class="recipe-card pa-10 mx-auto mt-10" max-width="950" elevation="1">
|
<v-card class="recipe-card pa-6 mx-auto mt-4" max-width="950" elevation="1">
|
||||||
<header class="text-center mb-10">
|
<header class="text-center mb-4">
|
||||||
<v-img
|
<v-img
|
||||||
src="/images/seasoned-logo.png"
|
src="/images/seasoned-logo.png"
|
||||||
width="180"
|
width="180"
|
||||||
@@ -12,10 +12,10 @@
|
|||||||
<p class="brand-subtitle">Kitchen Consultation</p>
|
<p class="brand-subtitle">Kitchen Consultation</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<v-divider class="mb-10 separator"></v-divider>
|
<v-divider class="mb-6 separator"></v-divider>
|
||||||
|
|
||||||
<v-row justify="center" class="mb-6">
|
<v-row justify="center" class="mb-6">
|
||||||
<v-col cols="12" md="10">
|
<v-col cols="12" md="11">
|
||||||
<div class="chat-container">
|
<div class="chat-container">
|
||||||
<div class="section-header mb-4 d-flex align-center">
|
<div class="section-header mb-4 d-flex align-center">
|
||||||
<v-icon icon="mdi-chef-hat" class="mr-2" size="small"></v-icon>
|
<v-icon icon="mdi-chef-hat" class="mr-2" size="small"></v-icon>
|
||||||
@@ -29,6 +29,13 @@
|
|||||||
<div v-for="(msg, i) in chatMessages" :key="i" :class="['message', msg.role]">
|
<div v-for="(msg, i) in chatMessages" :key="i" :class="['message', msg.role]">
|
||||||
<span class="message-text">{{ msg.text }}</span>
|
<span class="message-text">{{ msg.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="chatLoading" class="message assistant thinking-bubble">
|
||||||
|
<div class="typing">
|
||||||
|
<span class="dot"></span>
|
||||||
|
<span class="dot"></span>
|
||||||
|
<span class="dot"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-textarea
|
<v-textarea
|
||||||
@@ -39,16 +46,14 @@
|
|||||||
max-rows="6"
|
max-rows="6"
|
||||||
hide-details
|
hide-details
|
||||||
class="chat-input"
|
class="chat-input"
|
||||||
@keyup.enter.exact.prevent="askChef"
|
@keydown.enter.exact.prevent="askChef"
|
||||||
:loading="chatLoading"
|
:loading="chatLoading"
|
||||||
>
|
>
|
||||||
<template v-slot:append-inner>
|
<template v-slot:append-inner>
|
||||||
<v-btn
|
<v-btn
|
||||||
icon="mdi-send-variant"
|
icon="mdi-send-variant"
|
||||||
variant="text"
|
variant="text"
|
||||||
size="small"
|
class="mt-1 send-btn"
|
||||||
color="#8c4a32"
|
|
||||||
class="mt-1"
|
|
||||||
@click="askChef"
|
@click="askChef"
|
||||||
></v-btn>
|
></v-btn>
|
||||||
</template>
|
</template>
|
||||||
@@ -88,8 +93,7 @@ const askChef = async () => {
|
|||||||
userQuery.value = ''
|
userQuery.value = ''
|
||||||
chatLoading.value = true
|
chatLoading.value = true
|
||||||
|
|
||||||
await nextTick()
|
await scrollToBottom()
|
||||||
scrollToBottom()
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = await $fetch(`${config.public.apiBase}api/recipe/consult`, {
|
const data = await $fetch(`${config.public.apiBase}api/recipe/consult`, {
|
||||||
@@ -105,9 +109,6 @@ const askChef = async () => {
|
|||||||
localStorage.removeItem('pending_recipe')
|
localStorage.removeItem('pending_recipe')
|
||||||
}
|
}
|
||||||
|
|
||||||
await nextTick()
|
|
||||||
scrollToBottom()
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
chatMessages.value.push({
|
chatMessages.value.push({
|
||||||
role: 'assistant',
|
role: 'assistant',
|
||||||
@@ -115,12 +116,22 @@ const askChef = async () => {
|
|||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
chatLoading.value = false
|
chatLoading.value = false
|
||||||
|
await scrollToBottom()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollToBottom = () => {
|
const scrollToBottom = async () => {
|
||||||
|
await nextTick()
|
||||||
if (chatDisplay.value) {
|
if (chatDisplay.value) {
|
||||||
chatDisplay.value.scrollTop = chatDisplay.value.scrollHeight
|
const { scrollTop, scrollHeight, clientHeight } = chatDisplay.value
|
||||||
|
const isAtBottom = scrollHeight - scrollTop <= clientHeight + 100
|
||||||
|
|
||||||
|
if (isAtBottom) {
|
||||||
|
chatDisplay.value.scrollTo({
|
||||||
|
top: scrollHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
Turn handwritten cards into searchable digital text instantly.
|
Turn handwritten cards into searchable digital text instantly.
|
||||||
</p>
|
</p>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn v-if="isLoggedIn" to="/uploader" class="mt-12 column-button">
|
<v-btn v-if="isLoggedIn" to="/uploader" class="mt-12 column-btn">
|
||||||
Got to Uploader
|
Got to Uploader
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
Chat with an AI chef to scale ingredients, find substitutes, or get inspiration.
|
Chat with an AI chef to scale ingredients, find substitutes, or get inspiration.
|
||||||
</p>
|
</p>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn v-if="isLoggedIn" to="/chat" class="mt-12 column-button">
|
<v-btn v-if="isLoggedIn" to="/chat" class="mt-12 column-btn">
|
||||||
Talk to Chef
|
Talk to Chef
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
@@ -50,13 +50,13 @@
|
|||||||
Build a private collection that keeps your family traditions alive and organized.
|
Build a private collection that keeps your family traditions alive and organized.
|
||||||
</p>
|
</p>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-btn v-if="isLoggedIn" to="/gallery" class="mt-12 column-button">
|
<v-btn v-if="isLoggedIn" to="/gallery" class="mt-12 column-btn">
|
||||||
View Collection
|
View Collection
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<div v-if="!isLoggedIn" class="d-flex flex-column align-center">
|
<div v-if="!isLoggedIn" class="d-flex flex-column align-center">
|
||||||
<v-btn to="/login" class="analyze-btn px-12 py-6 mb-4" size="x-large">
|
<v-btn to="/login" class="column-btn" size="x-large">
|
||||||
Get Started
|
Get Started
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,43 +1,92 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container class="fill-height">
|
<v-container class="fill-height">
|
||||||
<v-card class="recipe-card auth-card pa-10 mx-auto" elevation="10" max-width="500">
|
<v-card theme="light" class="recipe-card auth-card pa-10 mx-auto" elevation="10" max-width="500">
|
||||||
|
|
||||||
<v-fade-transition mode="out-in">
|
<v-fade-transition mode="out-in">
|
||||||
<div :key="isLogin">
|
<div :key="isLogin">
|
||||||
<header class="text-center mb-8">
|
<header class="text-center mb-10">
|
||||||
|
<div class="brand-icon-container mb-1">
|
||||||
|
<v-img
|
||||||
|
src="/images/seasoned-logo.png"
|
||||||
|
width="180"
|
||||||
|
class="mx-auto"
|
||||||
|
contain
|
||||||
|
></v-img>
|
||||||
|
</div>
|
||||||
<h1 class="auth-title">{{ isLogin ? 'Sign In' : 'Join Us' }}</h1>
|
<h1 class="auth-title">{{ isLogin ? 'Sign In' : 'Join Us' }}</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<v-form @submit.prevent="handleAuth">
|
<v-form @submit.prevent="handleAuth">
|
||||||
|
<v-expand-transition>
|
||||||
|
<div v-if="errorMessage"
|
||||||
|
:class="[
|
||||||
|
'auth-message',
|
||||||
|
errorMessage.includes('created') ? 'auth-success' : 'auth-error'
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
:icon="errorMessage.includes('created') ? 'mdi-check-circle-outline' : 'mdi-alert-circle-outline'"
|
||||||
|
size="small"
|
||||||
|
class="mr-2"
|
||||||
|
></v-icon>
|
||||||
|
{{ errorMessage }}
|
||||||
|
</div>
|
||||||
|
</v-expand-transition>
|
||||||
|
|
||||||
<v-text-field
|
<v-text-field
|
||||||
autofocus
|
autofocus
|
||||||
v-model="email"
|
v-model="email"
|
||||||
placeholder="Email"
|
label="Email Address"
|
||||||
bg-color="#5d4037"
|
class="mb-4 auth-input"
|
||||||
base-color="#f8f1e0"
|
color="#8c4a32"
|
||||||
class="auth-input mb-4"
|
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
hide-details
|
|
||||||
prepend-inner-icon="mdi-email-outline"
|
prepend-inner-icon="mdi-email-outline"
|
||||||
|
@input="errorMessage = ''"
|
||||||
|
:style="{
|
||||||
|
caretColor: '#2e1e0a !important',
|
||||||
|
fontFamily: 'Libre Baskerville, serif !important'
|
||||||
|
}"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
|
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="password"
|
v-model="password"
|
||||||
placeholder="Password"
|
label="Password"
|
||||||
bg-color="#5d4037"
|
|
||||||
base-color="#f8f1e0"
|
|
||||||
type="password"
|
type="password"
|
||||||
class="auth-input mb-6"
|
class="mb-8 auth-input"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
color="#8c4a32"
|
||||||
hide-details
|
hide-details
|
||||||
prepend-inner-icon="mdi-lock-outline"
|
prepend-inner-icon="mdi-lock-outline"
|
||||||
|
@input="errorMessage = ''"
|
||||||
|
:style="{
|
||||||
|
caretColor: '#2e1e0a !important',
|
||||||
|
fontFamily: 'Libre Baskerville, serif !important'
|
||||||
|
}"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
|
|
||||||
|
<v-expand-transition>
|
||||||
|
<v-text-field
|
||||||
|
v-if="!isLogin"
|
||||||
|
v-model="confirmPassword"
|
||||||
|
label="Confirm Password"
|
||||||
|
type="password"
|
||||||
|
class="mb-8 auth-input"
|
||||||
|
variant="outlined"
|
||||||
|
color="#8c4a32"
|
||||||
|
hide-details
|
||||||
|
prepend-inner-icon="mdi-lock-check-outline"
|
||||||
|
@input="errorMessage = ''"
|
||||||
|
:style="{
|
||||||
|
caretColor: '#2e1e0a !important',
|
||||||
|
fontFamily: 'Libre Baskerville, serif !important'
|
||||||
|
}"
|
||||||
|
></v-text-field>
|
||||||
|
</v-expand-transition>
|
||||||
|
|
||||||
<v-btn
|
<v-btn
|
||||||
block
|
block
|
||||||
class="analyze-btn mb-4"
|
class="auth-btn mb-4"
|
||||||
size="large"
|
size="large"
|
||||||
elevation="0"
|
|
||||||
type="submit"
|
type="submit"
|
||||||
:loading="authLoading"
|
:loading="authLoading"
|
||||||
:disabled="authLoading"
|
:disabled="authLoading"
|
||||||
@@ -67,14 +116,29 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import '@/assets/css/login.css'
|
import '@/assets/css/login.css'
|
||||||
|
import '@/assets/css/app-theme.css'
|
||||||
|
|
||||||
const isLogin = ref(true)
|
const isLogin = ref(true)
|
||||||
const email = ref('')
|
const email = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
|
const confirmPassword = ref('')
|
||||||
|
const errorMessage = ref('')
|
||||||
const authLoading = ref(false)
|
const authLoading = ref(false)
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
|
|
||||||
|
const toggleMode = () => {
|
||||||
|
isLogin.value = !isLogin.value
|
||||||
|
errorMessage.value = ''
|
||||||
|
confirmPassword.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
const handleAuth = async () => {
|
const handleAuth = async () => {
|
||||||
|
errorMessage.value = ''
|
||||||
|
if (!isLogin.value && password.value !== confirmPassword.value) {
|
||||||
|
errorMessage.value = "Passwords do not match."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
authLoading.value = true
|
authLoading.value = true
|
||||||
const endpoint = isLogin.value ? 'api/auth/login' : 'api/auth/register'
|
const endpoint = isLogin.value ? 'api/auth/login' : 'api/auth/register'
|
||||||
|
|
||||||
@@ -98,9 +162,18 @@ const handleAuth = async () => {
|
|||||||
} else {
|
} else {
|
||||||
isLogin.value = true
|
isLogin.value = true
|
||||||
authLoading.value = false
|
authLoading.value = false
|
||||||
|
errorMessage.value = "Account created! Please sign in."
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
authLoading.value = false
|
authLoading.value = false
|
||||||
|
if (err.status === 401) {
|
||||||
|
errorMessage.value = "Invalid email or password. Please try again."
|
||||||
|
} else if (err.status === 404) {
|
||||||
|
errorMessage.value = "Account not found. Would you like to register?"
|
||||||
|
} else {
|
||||||
|
errorMessage.value = "Something went wrong. Please check your connection."
|
||||||
|
}
|
||||||
|
|
||||||
console.error('Auth error:', err)
|
console.error('Auth error:', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user