Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Alba María Álvarez
/
front_recipes
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
8dfe0fb6
authored
Aug 24, 2025
by
Alba María Álvarez
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
feat(RecipeDetail): creada la vista para ver recetas en detalle, editarlas y eliminarlas.
parent
22f445df
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
252 additions
and
0 deletions
src/views/RecipeDetail.vue
src/views/RecipeDetail.vue
0 → 100644
View file @
8dfe0fb6
<
template
>
<Header></Header>
<div
class=
"container my-5"
>
<div
class=
"row justify-content-center"
>
<div
class=
"col-lg-10 col-md-11"
>
<div
class=
"card h-100 card-custom"
>
<div
class=
"card-body p-5"
>
<div
class=
"d-flex justify-content-end mb-4"
>
<div
v-if=
"mode === 'view'"
class=
"d-flex gap-2"
>
<button
@
click=
"editRecipe"
class=
"btn btn-outline-custom"
>
<i
class=
"bi bi-pencil-square"
></i>
Editar
</button>
<button
@
click=
"deleteRecipe"
class=
"btn btn-danger"
>
<i
class=
"bi bi-trash"
></i>
Eliminar
</button>
</div>
<div
v-else
class=
"d-flex gap-2"
>
<button
@
click=
"saveChanges"
class=
"btn btn-primary-custom"
>
<i
class=
"bi bi-save"
></i>
Guardar
</button>
<button
@
click=
"mode = 'view'"
class=
"btn btn-secondary"
>
<i
class=
"bi bi-x-circle"
></i>
Cancelar
</button>
</div>
</div>
<div
class=
"text-center mb-4"
>
<h2
v-if=
"mode === 'view'"
class=
"fw-bolder mb-2 text-primary-custom"
>
{{
recipe
.
name
}}
</h2>
<input
v-else
type=
"text"
v-model=
"recipe.name"
class=
"form-control form-control-lg text-center mb-2"
/>
<div
class=
"d-flex small text-warning mb-4 justify-content-center"
>
<div
class=
"bi-star-fill me-1"
></div>
<div
class=
"bi-star-fill me-1"
></div>
<div
class=
"bi-star-fill me-1"
></div>
<div
class=
"bi-star-fill me-1"
></div>
<div
class=
"bi-star-fill"
></div>
</div>
<div
class=
"mb-4"
>
<img
v-if=
"mode === 'view'"
:src=
"recipe.image"
class=
"img-fluid rounded shadow-sm"
style=
"max-height: 500px; max-width: 100%; object-fit: cover;"
alt=
"Imagen de la receta"
/>
<div
v-else
class=
"text-center d-flex flex-column align-items-center"
>
<label
class=
"form-label fw-bold"
>
Cambiar imagen
</label>
<input
type=
"file"
class=
"form-control"
/>
</div>
</div>
<p
v-if=
"mode === 'view'"
class=
"text-muted"
>
{{
recipe
.
description
}}
</p>
<textarea
v-else
v-model=
"recipe.description"
@
input=
"autoGrow"
class=
"form-control mb-2"
rows=
"4"
>
</textarea>
</div>
<hr
class=
"my-4"
/>
<div
class=
"row"
>
<div
class=
"col-lg-6"
>
<div
class=
"mb-4"
>
<h5
class=
"fw-bold"
>
Ingredientes
</h5>
<ul
v-if=
"mode === 'view'"
class=
"list-unstyled"
>
<li
v-for=
"(ing, index) in recipe.ingredients"
:key=
"index"
class=
"mb-1"
>
<i
class=
"bi bi-check-circle-fill me-2 text-success"
></i>
{{
ing
.
quantity
}}
{{
ing
.
unit
}}
de
{{
ing
.
ingredient
}}
</li>
</ul>
<div
v-else
class=
"ingredient-form-section"
>
<div
v-for=
"(ing, index) in recipe.ingredients"
:key=
"index"
class=
"input-group mb-2"
>
<input
type=
"number"
v-model=
"ing.quantity"
class=
"form-control"
placeholder=
"Cantidad"
>
<input
type=
"text"
v-model=
"ing.unit"
class=
"form-control"
placeholder=
"Unidad"
>
<input
type=
"text"
v-model=
"ing.ingredient"
class=
"form-control"
placeholder=
"Ingrediente"
>
<button
@
click=
"recipe.ingredients.splice(index, 1)"
class=
"btn btn-outline-danger"
type=
"button"
><i
class=
"bi bi-trash"
></i></button>
</div>
<button
@
click=
"recipe.ingredients.push(
{ quantity: '', unit: '', ingredient: '' })" class="btn btn-outline-primary-custom mt-2 w-100">
<i
class=
"bi bi-plus-circle"
></i>
Añadir Ingrediente
</button>
</div>
</div>
</div>
<div
class=
"col-lg-6"
>
<div
class=
"mb-4"
>
<h5
class=
"fw-bold"
>
Pasos de Preparación
</h5>
<ol
v-if=
"mode === 'view'"
>
<li
v-for=
"(step, index) in recipe.steps"
:key=
"index"
class=
"mb-2"
>
{{
step
.
description
}}
</li>
</ol>
<div
v-else
class=
"steps-form-section"
>
<div
v-for=
"(step, index) in recipe.steps"
:key=
"index"
class=
"input-group mb-2"
>
<span
class=
"input-group-text"
>
{{
index
+
1
}}
</span>
<textarea
v-model=
"step.description"
@
input=
"autoGrow"
class=
"form-control"
rows=
"1"
>
</textarea>
<button
@
click=
"removeStep"
class=
"btn btn-outline-danger"
type=
"button"
><i
class=
"bi bi-trash"
></i></button>
</div>
<button
@
click=
"addStep"
class=
"btn btn-outline-primary-custom mt-2 w-100"
>
<i
class=
"bi bi-plus-circle"
></i>
Añadir Paso
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
}
from
'vue'
;
import
Header
from
'@/components/Header.vue'
;
// Estado de la vista: 'view' o 'edit'
const
mode
=
ref
(
'view'
);
// Datos de la receta de ejemplo
const
recipe
=
ref
({
name
:
'Tarta de Manzana Clásica'
,
image
:
'/src/assets/default recipe.jpg'
,
description
:
'Una deliciosa tarta de manzana con un toque de canela y una corteza dorada y crujiente.'
,
ingredients
:
[
{
quantity
:
2
,
unit
:
'tazas'
,
ingredient
:
'harina de trigo'
},
{
quantity
:
1
,
unit
:
'taza'
,
ingredient
:
'azúcar'
},
{
quantity
:
4
,
unit
:
'unidades'
,
ingredient
:
'manzanas'
}
],
steps
:
[
{
description
:
'Precalentar el horno a 180°C.'
},
{
description
:
'Mezclar la harina y el azúcar en un bol.'
},
{
description
:
'Pelar y cortar las manzanas en rodajas finas.'
},
{
description
:
'Hornear por 45 minutos.'
}
]
});
// Función para el textarea
const
autoGrow
=
(
event
)
=>
{
const
textarea
=
event
.
target
;
textarea
.
style
.
height
=
'auto'
;
// Resetea la altura
textarea
.
style
.
height
=
`
${
textarea
.
scrollHeight
}
px`
;
// Ajusta a la altura del contenido
};
// Lógica de los botones
const
editRecipe
=
()
=>
{
mode
.
value
=
'edit'
;
nextTick
(()
=>
{
// Selecciona todos los textareas y aplica la función
document
.
querySelectorAll
(
'textarea'
).
forEach
(
textarea
=>
{
autoGrow
({
target
:
textarea
});
});
});
};
const
saveChanges
=
()
=>
{
console
.
log
(
'Guardando cambios:'
,
recipe
.
value
);
mode
.
value
=
'view'
;
};
const
deleteRecipe
=
()
=>
{
console
.
log
(
'Eliminando la receta:'
,
recipe
.
value
.
name
);
};
const
addStep
=
()
=>
{
recipe
.
value
.
steps
.
push
({
description
:
''
});
nextTick
(()
=>
{
// Aplica el auto-crecimiento al nuevo textarea
const
newTextarea
=
document
.
querySelector
(
'.steps-form-section textarea:last-child'
);
if
(
newTextarea
)
{
autoGrow
({
target
:
newTextarea
});
}
});
};
const
removeStep
=
(
index
)
=>
{
recipe
.
value
.
steps
.
splice
(
index
,
1
);
};
</
script
>
<
style
scoped
>
.card-custom
{
border-color
:
#793E6C
;
box-shadow
:
0
0
1rem
rgba
(
121
,
62
,
108
,
0.1
);
border-radius
:
1rem
;
}
.text-primary-custom
{
color
:
#2C0C21
;
}
.btn-primary-custom
{
background-color
:
#793E6C
;
border-color
:
#793E6C
;
color
:
white
;
}
.btn-primary-custom
:hover
{
background-color
:
#5e3054
;
border-color
:
#5e3054
;
color
:
white
;
}
.btn-outline-custom
{
border-color
:
#793E6C
;
color
:
#793E6C
;
}
.btn-outline-custom
:hover
{
background-color
:
#793E6C
;
color
:
white
;
}
.form-control
:focus
{
border-color
:
#793E6C
;
box-shadow
:
0
0
0
0.25rem
rgba
(
121
,
62
,
108
,
0.25
);
}
h2
{
font-size
:
2.5rem
;
font-weight
:
700
;
}
h5
{
font-size
:
1.5rem
;
color
:
#2C0C21
;
}
.img-fluid
{
border-radius
:
0.5rem
;
}
/* Modo de edición (ingredientes y pasos horizontalmente) */
.ingredient-form-section
.input-group
,
.steps-form-section
.input-group
{
flex-wrap
:
nowrap
;
}
textarea
{
resize
:
none
;
overflow
:
hidden
;
}
</
style
>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment