Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
Dishly
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
2
Issues
2
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
O Bar da Lora
Dishly
Commits
ccf0bf5c
Commit
ccf0bf5c
authored
Jun 11, 2026
by
Natã Frederico Sangalletti
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Versão Final
parent
2c2ea596
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
471 additions
and
192 deletions
+471
-192
app.py
app.py
+185
-38
style.css
static/style.css
+0
-0
base.html
templates/base.html
+51
-0
cadastro.html
templates/cadastro.html
+36
-34
editar.html
templates/editar.html
+49
-40
index.html
templates/index.html
+42
-68
perfil.html
templates/perfil.html
+54
-12
receita.html
templates/receita.html
+54
-0
No files found.
app.py
View file @
ccf0bf5c
import
os
from
flask
import
Flask
,
redirect
,
render_template
,
request
,
url_for
from
flask
import
Flask
,
flash
,
redirect
,
render_template
,
request
,
url_for
from
flask_sqlalchemy
import
SQLAlchemy
from
sqlalchemy
import
func
,
text
app
=
Flask
(
__name__
)
app
.
config
[
"SECRET_KEY"
]
=
os
.
environ
.
get
(
"SECRET_KEY"
,
"dishly-dev-key"
)
app
.
config
[
"SQLALCHEMY_DATABASE_URI"
]
=
"sqlite:///"
+
os
.
path
.
join
(
app
.
instance_path
,
"database.db"
)
...
...
@@ -11,7 +12,9 @@ app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db
=
SQLAlchemy
(
app
)
# Modelo da Tabela
CATEGORIAS
=
[
"Todos"
,
"Doces"
,
"Salgados"
,
"Bebidas"
]
class
Receita
(
db
.
Model
):
id
=
db
.
Column
(
db
.
Integer
,
primary_key
=
True
)
nome
=
db
.
Column
(
db
.
String
(
100
),
nullable
=
False
)
...
...
@@ -20,71 +23,215 @@ class Receita(db.Model):
descricao
=
db
.
Column
(
db
.
Text
,
nullable
=
False
)
ingredientes
=
db
.
Column
(
db
.
Text
,
nullable
=
False
)
preparo
=
db
.
Column
(
db
.
Text
,
nullable
=
False
)
categoria
=
db
.
Column
(
db
.
String
(
50
),
nullable
=
False
,
default
=
"Salgados"
)
def
_ensure_categoria_column
():
with
db
.
engine
.
connect
()
as
conn
:
cols
=
conn
.
execute
(
text
(
"PRAGMA table_info(receita)"
))
.
fetchall
()
if
cols
and
not
any
(
col
[
1
]
==
"categoria"
for
col
in
cols
):
conn
.
execute
(
text
(
"ALTER TABLE receita ADD COLUMN categoria VARCHAR(50) DEFAULT 'Salgados'"
)
)
conn
.
commit
()
def
_parse_receita_form
():
nome
=
(
request
.
form
.
get
(
"nome"
)
or
""
)
.
strip
()
porcoes
=
(
request
.
form
.
get
(
"porcoes"
)
or
""
)
.
strip
()
tempo
=
(
request
.
form
.
get
(
"tempo"
)
or
""
)
.
strip
()
descricao
=
(
request
.
form
.
get
(
"descricao"
)
or
""
)
.
strip
()
ingredientes
=
(
request
.
form
.
get
(
"ingredientes"
)
or
""
)
.
strip
()
preparo
=
(
request
.
form
.
get
(
"preparo"
)
or
""
)
.
strip
()
categoria
=
(
request
.
form
.
get
(
"categoria"
)
or
"Salgados"
)
.
strip
()
if
categoria
not
in
CATEGORIAS
[
1
:]:
categoria
=
"Salgados"
erros
=
[]
if
not
nome
:
erros
.
append
(
"Informe o nome da receita."
)
if
not
porcoes
:
erros
.
append
(
"Informe o número de porções."
)
if
not
tempo
:
erros
.
append
(
"Informe o tempo de preparo."
)
if
not
descricao
:
erros
.
append
(
"Informe uma descrição."
)
if
not
ingredientes
:
erros
.
append
(
"Informe os ingredientes."
)
if
not
preparo
:
erros
.
append
(
"Informe o modo de preparo."
)
return
{
"nome"
:
nome
,
"porcoes"
:
porcoes
,
"tempo"
:
tempo
,
"descricao"
:
descricao
,
"ingredientes"
:
ingredientes
,
"preparo"
:
preparo
,
"categoria"
:
categoria
,
"erros"
:
erros
,
}
def
_filtrar_receitas
():
busca
=
(
request
.
args
.
get
(
"q"
)
or
""
)
.
strip
()
categoria
=
(
request
.
args
.
get
(
"categoria"
)
or
"Todos"
)
.
strip
()
query
=
Receita
.
query
if
categoria
in
CATEGORIAS
[
1
:]:
query
=
query
.
filter
(
Receita
.
categoria
==
categoria
)
if
busca
:
termo
=
f
"
%
{busca.lower()}
%
"
query
=
query
.
filter
(
db
.
or_
(
func
.
lower
(
Receita
.
nome
)
.
like
(
termo
),
func
.
lower
(
Receita
.
descricao
)
.
like
(
termo
),
func
.
lower
(
Receita
.
ingredientes
)
.
like
(
termo
),
)
)
return
query
.
order_by
(
Receita
.
id
.
desc
())
.
all
(),
busca
,
categoria
@app.route
(
"/"
)
def
index
():
receitas
=
Receita
.
query
.
all
()
return
render_template
(
"index.html"
,
receitas
=
receitas
)
receitas
,
busca
,
categoria
=
_filtrar_receitas
()
return
render_template
(
"index.html"
,
receitas
=
receitas
,
busca
=
busca
,
categoria_ativa
=
categoria
,
categorias
=
CATEGORIAS
,
)
@app.route
(
"/receita/<int:id>"
)
def
receita
(
id
):
receita_obj
=
Receita
.
query
.
get_or_404
(
id
)
return
render_template
(
"receita.html"
,
receita
=
receita_obj
)
@app.route
(
"/cadastro"
,
methods
=
[
"GET"
,
"POST"
])
def
cadastro
():
if
request
.
method
==
"POST"
:
nome
=
request
.
form
.
get
(
"nome"
)
porcoes
=
request
.
form
.
get
(
"porcoes"
)
tempo
=
request
.
form
.
get
(
"tempo"
)
descricao
=
request
.
form
.
get
(
"descricao"
)
ingredientes
=
request
.
form
.
get
(
"ingredientes"
)
preparo
=
request
.
form
.
get
(
"preparo"
)
dados
=
{
"nome"
:
""
,
"porcoes"
:
""
,
"tempo"
:
""
,
"descricao"
:
""
,
"ingredientes"
:
""
,
"preparo"
:
""
,
"categoria"
:
"Salgados"
,
}
print
(
f
"DADOS RECEBIDOS: {nome}, {porcoes}, {tempo}, {descricao}, {ingredientes}, {preparo}"
)
if
request
.
method
==
"POST"
:
dados
=
_parse_receita_form
()
if
dados
[
"erros"
]:
for
erro
in
dados
[
"erros"
]:
flash
(
erro
,
"erro"
)
return
render_template
(
"cadastro.html"
,
dados
=
dados
,
categorias
=
CATEGORIAS
[
1
:]
)
nova
=
Receita
(
nome
=
nome
,
porcoes
=
porcoes
,
tempo
=
tempo
,
descricao
=
descricao
,
ingredientes
=
ingredientes
,
preparo
=
preparo
,
nome
=
dados
[
"nome"
],
porcoes
=
dados
[
"porcoes"
],
tempo
=
dados
[
"tempo"
],
descricao
=
dados
[
"descricao"
],
ingredientes
=
dados
[
"ingredientes"
],
preparo
=
dados
[
"preparo"
],
categoria
=
dados
[
"categoria"
],
)
db
.
session
.
add
(
nova
)
db
.
session
.
commit
()
return
redirect
(
url_for
(
"index"
))
flash
(
"Receita cadastrada com sucesso!"
,
"sucesso"
)
return
redirect
(
url_for
(
"receita"
,
id
=
nova
.
id
))
return
render_template
(
"cadastro.html"
,
dados
=
dados
,
categorias
=
CATEGORIAS
[
1
:])
return
render_template
(
"cadastro.html"
)
@app.route
(
"/editar/<int:id>"
,
methods
=
[
"GET"
,
"POST"
])
def
editar
(
id
):
receita
=
Receita
.
query
.
get_or_404
(
id
)
receita
_obj
=
Receita
.
query
.
get_or_404
(
id
)
if
request
.
method
==
"POST"
:
receita
.
nome
=
request
.
form
.
get
(
"nome"
)
receita
.
porcoes
=
request
.
form
.
get
(
"porcoes"
)
receita
.
tempo
=
request
.
form
.
get
(
"tempo"
)
receita
.
descricao
=
request
.
form
.
get
(
"descricao"
)
receita
.
ingredientes
=
request
.
form
.
get
(
"ingredientes"
)
receita
.
preparo
=
request
.
form
.
get
(
"preparo"
)
dados
=
_parse_receita_form
()
if
dados
[
"erros"
]:
for
erro
in
dados
[
"erros"
]:
flash
(
erro
,
"erro"
)
return
render_template
(
"editar.html"
,
receita
=
receita_obj
,
dados
=
dados
,
categorias
=
CATEGORIAS
[
1
:],
)
receita_obj
.
nome
=
dados
[
"nome"
]
receita_obj
.
porcoes
=
dados
[
"porcoes"
]
receita_obj
.
tempo
=
dados
[
"tempo"
]
receita_obj
.
descricao
=
dados
[
"descricao"
]
receita_obj
.
ingredientes
=
dados
[
"ingredientes"
]
receita_obj
.
preparo
=
dados
[
"preparo"
]
receita_obj
.
categoria
=
dados
[
"categoria"
]
db
.
session
.
commit
()
return
redirect
(
url_for
(
"index"
))
flash
(
"Receita atualizada com sucesso!"
,
"sucesso"
)
return
redirect
(
url_for
(
"receita"
,
id
=
receita_obj
.
id
))
dados
=
{
"nome"
:
receita_obj
.
nome
,
"porcoes"
:
receita_obj
.
porcoes
,
"tempo"
:
receita_obj
.
tempo
,
"descricao"
:
receita_obj
.
descricao
,
"ingredientes"
:
receita_obj
.
ingredientes
,
"preparo"
:
receita_obj
.
preparo
,
"categoria"
:
receita_obj
.
categoria
or
"Salgados"
,
}
return
render_template
(
"editar.html"
,
receita
=
receita_obj
,
dados
=
dados
,
categorias
=
CATEGORIAS
[
1
:],
)
return
render_template
(
"editar.html"
,
receita
=
receita
)
@app.route
(
"/excluir/<int:id>"
)
@app.route
(
"/excluir/<int:id>"
,
methods
=
[
"POST"
]
)
def
excluir
(
id
):
receita
=
Receita
.
query
.
get_or_404
(
id
)
db
.
session
.
delete
(
receita
)
receita_obj
=
Receita
.
query
.
get_or_404
(
id
)
nome
=
receita_obj
.
nome
db
.
session
.
delete
(
receita_obj
)
db
.
session
.
commit
()
flash
(
f
'Receita "{nome}" excluída.'
,
"sucesso"
)
return
redirect
(
url_for
(
"index"
))
@app.route
(
"/perfil"
)
def
acessoPerfil
():
return
render_template
(
"perfil.html"
)
@app.route
(
"/perfil"
)
def
perfil
():
total
=
Receita
.
query
.
count
()
por_categoria
=
(
db
.
session
.
query
(
Receita
.
categoria
,
func
.
count
(
Receita
.
id
))
.
group_by
(
Receita
.
categoria
)
.
all
()
)
recentes
=
Receita
.
query
.
order_by
(
Receita
.
id
.
desc
())
.
limit
(
5
)
.
all
()
return
render_template
(
"perfil.html"
,
total
=
total
,
por_categoria
=
por_categoria
,
recentes
=
recentes
,
)
if
__name__
==
"__main__"
:
def
init_db
()
:
os
.
makedirs
(
app
.
instance_path
,
exist_ok
=
True
)
with
app
.
app_context
():
db
.
create_all
()
_ensure_categoria_column
()
init_db
()
if
__name__
==
"__main__"
:
app
.
run
(
debug
=
True
)
static/style.css
View file @
ccf0bf5c
This diff is collapsed.
Click to expand it.
templates/base.html
0 → 100644
View file @
ccf0bf5c
<!doctype html>
<html
lang=
"pt-BR"
>
<head>
<meta
charset=
"UTF-8"
/>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
/>
<link
rel=
"stylesheet"
href=
"{{ url_for('static', filename='style.css') }}"
/>
<title>
{% block title %}Dishly{% endblock %}
</title>
</head>
<body
class=
"{% block body_class %}{% endblock %}"
>
{% block header %}
<header
class=
"header"
>
<a
class=
"header__user"
href=
"{{ url_for('perfil') }}"
title=
"Perfil"
>
<svg
width=
"22"
height=
"22"
viewBox=
"0 0 24 24"
fill=
"currentColor"
aria-hidden=
"true"
>
<path
d=
"M12 12c2.7 0 4.8-2.1 4.8-4.8S14.7 2.4 12 2.4 7.2 4.5 7.2 7.2 9.3 12 12 12zm0 2.4c-3.2 0-9.6 1.6-9.6 4.8v2.4h19.2v-2.4c0-3.2-6.4-4.8-9.6-4.8z"
/>
</svg>
</a>
<a
class=
"header__logo"
href=
"{{ url_for('index') }}"
>
Dishly
</a>
{% block search %}
<form
class=
"header__search"
action=
"{{ url_for('index') }}"
method=
"get"
role=
"search"
>
<svg
width=
"18"
height=
"18"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
stroke-width=
"2.5"
stroke-linecap=
"round"
stroke-linejoin=
"round"
aria-hidden=
"true"
>
<circle
cx=
"11"
cy=
"11"
r=
"8"
/>
<line
x1=
"21"
y1=
"21"
x2=
"16.65"
y2=
"16.65"
/>
</svg>
<input
type=
"search"
name=
"q"
value=
"{{ busca|default('') }}"
placeholder=
"Buscar receitas..."
aria-label=
"Buscar receitas"
/>
{% if categoria_ativa|default('Todos') != 'Todos' %}
<input
type=
"hidden"
name=
"categoria"
value=
"{{ categoria_ativa }}"
/>
{% endif %}
</form>
{% endblock %}
</header>
{% endblock %}
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div
class=
"flash-container"
role=
"status"
>
{% for categoria, mensagem in messages %}
<p
class=
"flash flash--{{ categoria }}"
>
{{ mensagem }}
</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
{% block footer %}
<footer>
<p>
©
2026 Dishly. Todos os direitos reservados.
</p>
</footer>
{% endblock %}
</body>
</html>
templates/cadastro.html
View file @
ccf0bf5c
<!doctype html>
<html
lang=
"pt-BR"
>
{% extends "base.html" %}
<head>
<meta
charset=
"UTF-8"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<link
rel=
"stylesheet"
href=
"/static/style.css"
>
<title>
Cadastro de Receita
</title>
</head>
{% block title %}Nova Receita — Dishly{% endblock %}
{% block body_class %}form-page{% endblock %}
<body
class=
"editar-page"
>
{% block header %}{% endblock %}
{% block footer %}{% endblock %}
<div
class=
"editar-container"
>
<form
class=
"editar-form"
action=
"/cadastro"
method=
"POST"
>
{% block content %}
<div
class=
"form-page__wrap"
>
<div
class=
"form-container"
>
<a
class=
"form-back"
href=
"{{ url_for('index') }}"
>
←
Voltar ao feed
</a>
<form
class=
"form-card"
action=
"{{ url_for('cadastro') }}"
method=
"POST"
>
<h1>
Nova Receita
</h1>
<p
class=
"form-subtitle"
>
Compartilhe sua receita com a comunidade Dishly.
</p>
<label
for=
"nome"
>
Nome da R
eceita
</label>
<input
id=
"nome"
name=
"nome"
type=
"text"
placeholder=
"Ex: Lasanha
"
required
>
<label
for=
"nome"
>
Nome da r
eceita
</label>
<input
id=
"nome"
name=
"nome"
type=
"text"
placeholder=
"Ex: Lasanha bolonhesa"
value=
"{{ dados.nome }}
"
required
>
<div
class=
"form-row"
>
<div>
<label
for=
"porcoes"
>
Porções
</label>
<input
id=
"porcoes"
name=
"porcoes"
type=
"text"
placeholder=
"Ex: 6 porções"
>
<input
id=
"porcoes"
name=
"porcoes"
type=
"text"
placeholder=
"Ex: 6 porções"
value=
"{{ dados.porcoes }}"
required
>
</div>
<div>
<label
for=
"tempo"
>
Tempo de preparo
</label>
<input
id=
"tempo"
name=
"tempo"
type=
"text"
placeholder=
"Ex: 45 minutos"
>
<input
id=
"tempo"
name=
"tempo"
type=
"text"
placeholder=
"Ex: 45 minutos"
value=
"{{ dados.tempo }}"
required
>
</div>
</div>
<label
for=
"categoria"
>
Categoria
</label>
<select
id=
"categoria"
name=
"categoria"
required
>
{% for cat in categorias %}
<option
value=
"{{ cat }}"
{%
if
dados
.
categoria =
=
cat
%}
selected
{%
endif
%}
>
{{ cat }}
</option>
{% endfor %}
</select>
<label
for=
"descricao"
>
Descrição
</label>
<input
id=
"descricao"
name=
"descricao"
type=
"text"
placeholder=
"Breve descrição da receita"
>
<textarea
id=
"descricao"
name=
"descricao"
placeholder=
"Breve descrição da receita"
required
>
{{ dados.descricao }}
</textarea
>
<label
for=
"ingredientes"
>
Ingredientes
</label>
<input
id=
"ingredientes"
name=
"ingredientes"
type=
"text"
placeholder=
"Liste os ingredientes"
>
<textarea
id=
"ingredientes"
name=
"ingredientes"
placeholder=
"Um ingrediente por linha"
required
>
{{ dados.ingredientes }}
</textarea
>
<label
for=
"preparo"
>
Modo de preparo
</label>
<input
id=
"preparo"
name=
"preparo"
type=
"text"
placeholder=
"Descreva o preparo"
>
<div
class=
"editar-botoes"
>
<button
class=
"btn-secundario"
type=
"reset"
>
Limpar
</button>
<textarea
id=
"preparo"
name=
"preparo"
placeholder=
"Descreva o passo a passo"
required
>
{{ dados.preparo }}
</textarea>
<button
class=
"btn-principal"
type=
"submit
"
>
Salvar
</button>
<div
class=
"form-actions
"
>
<button
class=
"btn-secundario"
type=
"reset"
>
Limpar
</button>
<button
class=
"btn-principal"
type=
"submit"
>
Salvar receita
</button>
</div>
</form>
</div>
</body>
</html>
\ No newline at end of file
</div>
{% endblock %}
templates/editar.html
View file @
ccf0bf5c
<!DOCTYPE html>
<html
lang=
"pt-BR"
>
{% extends "base.html" %}
<head>
<meta
charset=
"UTF-8"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<link
rel=
"stylesheet"
href=
"/static/style.css"
>
<title>
Editar Receita
</title>
</head>
{% block title %}Editar Receita — Dishly{% endblock %}
{% block body_class %}form-page{% endblock %}
<body
class=
"editar-page"
>
{% block header %}{% endblock %}
{% block footer %}{% endblock %}
<div
class=
"editar-container"
>
<form
class=
"editar-form"
action=
"/editar/{{ receita.id }}"
method=
"POST"
>
{% block content %}
<div
class=
"form-page__wrap"
>
<div
class=
"form-container"
>
<a
class=
"form-back"
href=
"{{ url_for('receita', id=receita.id) }}"
>
←
Voltar à receita
</a>
<form
class=
"form-card"
action=
"{{ url_for('editar', id=receita.id) }}"
method=
"POST"
>
<h1>
Editar Receita
</h1>
<p
class=
"form-subtitle"
>
Atualize os detalhes de {{ receita.nome }}.
</p>
<label
for=
"nome"
>
Nome da Receita
</label>
<input
id=
"nome"
name=
"nome"
type=
"text"
value=
"{{ receita.nome }}"
required
>
<div
class=
"editar-botoes"
>
<button
class=
"btn-secundario"
type=
"reset"
>
Limpar
</button>
<button
class=
"btn-principal"
type=
"submit"
>
Salvar
</button>
<button
class=
"btn-excluir"
type=
"button"
onclick=
"location.href='/excluir/{{ receita.id }}'"
>
Excluir
</button>
</div>
<label
for=
"nome"
>
Nome da receita
</label>
<input
id=
"nome"
name=
"nome"
type=
"text"
value=
"{{ dados.nome }}"
required
>
</form>
<div
class=
"form-row"
>
<div>
<label
for=
"porcoes"
>
Porções
</label>
<input
id=
"porcoes"
name=
"porcoes"
type=
"text"
value=
"{{ dados.porcoes }}"
required
>
</div>
<div>
<label
for=
"tempo"
>
Tempo de preparo
</label>
<input
id=
"tempo"
name=
"tempo"
type=
"text"
value=
"{{ dados.tempo }}"
required
>
</div>
</div>
<label
for=
"categoria"
>
Categoria
</label>
<select
id=
"categoria"
name=
"categoria"
required
>
{% for cat in categorias %}
<option
value=
"{{ cat }}"
{%
if
dados
.
categoria =
=
cat
%}
selected
{%
endif
%}
>
{{ cat }}
</option>
{% endfor %}
</select>
<label
for=
"descricao"
>
Descrição
</label>
<textarea
id=
"descricao"
name=
"descricao"
required
>
{{ dados.descricao }}
</textarea>
</body>
<label
for=
"ingredientes"
>
Ingredientes
</label>
<textarea
id=
"ingredientes"
name=
"ingredientes"
required
>
{{ dados.ingredientes }}
</textarea>
</html>
\ No newline at end of file
<label
for=
"preparo"
>
Modo de preparo
</label>
<textarea
id=
"preparo"
name=
"preparo"
required
>
{{ dados.preparo }}
</textarea>
<div
class=
"form-actions"
>
<button
class=
"btn-principal"
type=
"submit"
>
Salvar alterações
</button>
</div>
</form>
<form
class=
"form-delete"
action=
"{{ url_for('excluir', id=receita.id) }}"
method=
"POST"
onsubmit=
"return confirm('Tem certeza que deseja excluir esta receita?');"
>
<button
class=
"btn-excluir"
type=
"submit"
>
Excluir receita
</button>
</form>
</div>
</div>
{% endblock %}
templates/index.html
View file @
ccf0bf5c
<!doctype html>
<html
lang=
"pt-BR"
>
<head>
<meta
charset=
"UTF-8"
/>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
/>
<link
rel=
"stylesheet"
href=
"/static/style.css"
/>
<link
href=
"https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel=
"stylesheet"
integrity=
"sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB"
crossorigin=
"anonymous"
>
<title>
Dishly — Feed
</title>
</head>
{% extends "base.html" %}
<body>
<!-- Cabeçalho com logo e busca -->
<header
class=
"header"
>
<a
class=
"header_user"
href=
"/templates/perfil"
><img
src=
"{{ url_for('static', filename='img/user-solid.png') }}"
alt=
"Perfil"
width=
"30px"
></a>
<a
class=
"header__logo"
href=
"/"
>
Dishly
</a>
<div
class=
"header__search"
>
<!-- ícone de lupa -->
<svg
width=
"18"
height=
"18"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
stroke-width=
"2.5"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
<circle
cx=
"11"
cy=
"11"
r=
"8"
/>
<line
x1=
"21"
y1=
"21"
x2=
"16.65"
y2=
"16.65"
/>
</svg>
<input
type=
"text"
placeholder=
"Buscar receitas..."
/>
</div>
</header>
{% block title %}Dishly — Feed{% endblock %}
<!-- Navegação de categorias -->
<nav
class=
"nav
"
>
<a
href=
""
class=
"active"
>
Todos
</a>
<a
href=
""
>
Doces
</a>
<a
href=
""
>
Salgados
</a>
<a
href=
""
>
Bebidas
</a>
</nav>
{% block content %}
<nav
class=
"nav"
aria-label=
"Categorias
"
>
{% for cat in categorias %}
<a
href=
"{{ url_for('index', categoria=cat, q=busca) }}"
class=
"{% if categoria_ativa == cat %}active{% endif %}"
>
{{ cat }}
</a>
{% endfor %}
</nav>
<!-- Grade de receitas estilo Pinterest --
>
<main
class=
"feed"
>
<main
class=
"feed"
>
{% if receitas %}
{% for receita in receitas %}
<article
class=
"card"
>
<!-- Placeholder de imagem; substitua por <img src="{{ receita.imagem }}"> quando tiver imagens -->
<div
class=
"card__img"
>
<svg
width=
"40"
height=
"40"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"#999"
stroke-width=
"1.5"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
<a
class=
"card__link"
href=
"{{ url_for('receita', id=receita.id) }}"
>
<div
class=
"card__img card__img--{{ loop.index0 % 3 }}"
>
<span
class=
"card__categoria"
>
{{ receita.categoria or 'Salgados' }}
</span>
<svg
width=
"40"
height=
"40"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"#999"
stroke-width=
"1.5"
stroke-linecap=
"round"
stroke-linejoin=
"round"
aria-hidden=
"true"
>
<rect
x=
"3"
y=
"3"
width=
"18"
height=
"18"
rx=
"2"
/>
<circle
cx=
"8.5"
cy=
"8.5"
r=
"1.5"
/>
<polyline
points=
"21 15 16 10 5 21"
/>
</svg>
</div>
<!-- Overlay com ações que aparecem no hover -->
<div
class=
"card__overlay"
>
<div
class=
"card__overlay-top"
>
<
button
class=
"btn-salvar"
>
Salvar
</butto
n>
<
span
class=
"card__tempo"
>
{{ receita.tempo }}
</spa
n>
</div>
<div
class=
"card__overlay-bottom"
>
<a
class=
"btn-editar"
href=
"
/editar/{{ receita.id }}
"
>
Editar
</a>
<a
class=
"btn-editar"
href=
"
{{ url_for('editar', id=receita.id) }}"
onclick=
"event.stopPropagation()
"
>
Editar
</a>
</div>
</div>
<!-- Nome da receita -->
<div
class=
"card__info"
>
<p
class=
"card__title"
>
{{ receita.nome }}
</p>
<p
class=
"card__meta"
>
{{ receita.porcoes }}
</p>
</div>
</a>
</article>
{% endfor %}
</main>
{% else %}
<div
class=
"empty-state"
>
<svg
width=
"64"
height=
"64"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"#ccc"
stroke-width=
"1.5"
aria-hidden=
"true"
>
<path
d=
"M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"
/>
<line
x1=
"3"
y1=
"6"
x2=
"21"
y2=
"6"
/>
<path
d=
"M16 10a4 4 0 0 1-8 0"
/>
</svg>
<h2>
Nenhuma receita encontrada
</h2>
<p>
{% if busca or categoria_ativa != 'Todos' %}
Tente outra busca ou categoria.
{% else %}
Comece cadastrando sua primeira receita!
{% endif %}
</p>
<a
class=
"btn-principal btn-principal--inline"
href=
"{{ url_for('cadastro') }}"
>
Nova receita
</a>
</div>
{% endif %}
</main>
<!-- Botão flutuante para cadastrar nova receita -->
<a
class=
"fab"
href=
"/cadastro"
title=
"Nova receita"
>
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
stroke-width=
"2"
stroke-linecap=
"round"
stroke-linejoin=
"round"
>
<a
class=
"fab"
href=
"{{ url_for('cadastro') }}"
title=
"Nova receita"
aria-label=
"Nova receita"
>
<svg
width=
"24"
height=
"24"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"currentColor"
stroke-width=
"2"
stroke-linecap=
"round"
stroke-linejoin=
"round"
aria-hidden=
"true"
>
<line
x1=
"12"
y1=
"5"
x2=
"12"
y2=
"19"
/>
<line
x1=
"5"
y1=
"12"
x2=
"19"
y2=
"12"
/>
</svg>
</a>
<footer>
<p>
©
2026 Dishly. Todos os direitos reservados.
</p>
</footer>
</body>
</html>
</a>
{% endblock %}
templates/perfil.html
View file @
ccf0bf5c
<!DOCTYPE html>
<html
lang=
"pt-BR"
>
<head>
<meta
charset=
"UTF-8"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<title>
Perfil
</title>
</head>
<body>
</body>
</html>
\ No newline at end of file
{% extends "base.html" %}
{% block title %}Perfil — Dishly{% endblock %}
{% block body_class %}profile-page{% endblock %}
{% block search %}{% endblock %}
{% block content %}
<main
class=
"profile"
>
<div
class=
"profile__header"
>
<div
class=
"profile__avatar"
>
<svg
width=
"48"
height=
"48"
viewBox=
"0 0 24 24"
fill=
"currentColor"
aria-hidden=
"true"
>
<path
d=
"M12 12c2.7 0 4.8-2.1 4.8-4.8S14.7 2.4 12 2.4 7.2 4.5 7.2 7.2 9.3 12 12 12zm0 2.4c-3.2 0-9.6 1.6-9.6 4.8v2.4h19.2v-2.4c0-3.2-6.4-4.8-9.6-4.8z"
/>
</svg>
</div>
<div>
<h1>
Meu perfil
</h1>
<p>
Suas receitas no Dishly
</p>
</div>
</div>
<div
class=
"profile__stats"
>
<article
class=
"stat-card"
>
<strong>
{{ total }}
</strong>
<span>
Receitas cadastradas
</span>
</article>
{% for cat, qtd in por_categoria %}
<article
class=
"stat-card"
>
<strong>
{{ qtd }}
</strong>
<span>
{{ cat }}
</span>
</article>
{% endfor %}
</div>
<section
class=
"profile__recent"
>
<h2>
Receitas recentes
</h2>
{% if recentes %}
<ul
class=
"profile__list"
>
{% for receita in recentes %}
<li>
<a
href=
"{{ url_for('receita', id=receita.id) }}"
>
<span
class=
"profile__list-name"
>
{{ receita.nome }}
</span>
<span
class=
"profile__list-meta"
>
{{ receita.categoria }} · {{ receita.tempo }}
</span>
</a>
</li>
{% endfor %}
</ul>
{% else %}
<p
class=
"profile__empty"
>
Você ainda não cadastrou nenhuma receita.
</p>
<a
class=
"btn-principal btn-principal--inline"
href=
"{{ url_for('cadastro') }}"
>
Cadastrar receita
</a>
{% endif %}
</section>
</main>
{% endblock %}
templates/receita.html
0 → 100644
View file @
ccf0bf5c
{% extends "base.html" %}
{% block title %}{{ receita.nome }} — Dishly{% endblock %}
{% block body_class %}detail-page{% endblock %}
{% block search %}{% endblock %}
{% block content %}
<main
class=
"detail"
>
<div
class=
"detail__hero"
>
<div
class=
"detail__hero-img"
>
<svg
width=
"80"
height=
"80"
viewBox=
"0 0 24 24"
fill=
"none"
stroke=
"#bbb"
stroke-width=
"1.2"
aria-hidden=
"true"
>
<rect
x=
"3"
y=
"3"
width=
"18"
height=
"18"
rx=
"2"
/>
<circle
cx=
"8.5"
cy=
"8.5"
r=
"1.5"
/>
<polyline
points=
"21 15 16 10 5 21"
/>
</svg>
</div>
</div>
<div
class=
"detail__content"
>
<div
class=
"detail__header"
>
<span
class=
"detail__badge"
>
{{ receita.categoria or 'Salgados' }}
</span>
<h1>
{{ receita.nome }}
</h1>
<p
class=
"detail__desc"
>
{{ receita.descricao }}
</p>
<div
class=
"detail__meta"
>
<span>
{{ receita.porcoes }}
</span>
<span>
{{ receita.tempo }}
</span>
</div>
<div
class=
"detail__actions"
>
<a
class=
"btn-principal btn-principal--inline"
href=
"{{ url_for('editar', id=receita.id) }}"
>
Editar
</a>
<a
class=
"btn-secundario btn-secundario--inline"
href=
"{{ url_for('index') }}"
>
Voltar ao feed
</a>
</div>
</div>
<section
class=
"detail__section"
>
<h2>
Ingredientes
</h2>
<ul
class=
"detail__list"
>
{% for linha in receita.ingredientes.splitlines() if linha.strip() %}
<li>
{{ linha.strip() }}
</li>
{% endfor %}
</ul>
</section>
<section
class=
"detail__section"
>
<h2>
Modo de preparo
</h2>
<ol
class=
"detail__steps"
>
{% for passo in receita.preparo.splitlines() if passo.strip() %}
<li>
{{ passo.strip() }}
</li>
{% endfor %}
</ol>
</section>
</div>
</main>
{% endblock %}
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