V1 Mockup ai
This commit is contained in:
parent
39e04707ed
commit
feced6b0d6
Binary file not shown.
Binary file not shown.
@ -133,9 +133,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
LANGUAGE_CODE = 'pt-br'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
TIME_ZONE = 'America/Sao_Paulo'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
@ -180,3 +180,5 @@ if EMAIL_USE_SSL:
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
MEDIA_URL = 'media/'
|
||||
MEDIA_ROOT = BASE_DIR / 'media'
|
||||
|
||||
@ -27,3 +27,4 @@ urlpatterns = [
|
||||
if settings.DEBUG:
|
||||
urlpatterns += static("/assets/", document_root=settings.BASE_DIR / "assets")
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,3 +1,17 @@
|
||||
from django.contrib import admin
|
||||
from .models import MockupProject, MockupResult
|
||||
|
||||
# Register your models here.
|
||||
class MockupResultInline(admin.TabularInline):
|
||||
model = MockupResult
|
||||
extra = 0
|
||||
|
||||
@admin.register(MockupProject)
|
||||
class MockupProjectAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'user', 'status', 'created_at')
|
||||
list_filter = ('status', 'gender', 'body_type')
|
||||
search_fields = ('title', 'user__username')
|
||||
inlines = [MockupResultInline]
|
||||
|
||||
@admin.register(MockupResult)
|
||||
class MockupResultAdmin(admin.ModelAdmin):
|
||||
list_display = ('project', 'view_type', 'created_at')
|
||||
53
core/migrations/0001_initial.py
Normal file
53
core/migrations/0001_initial.py
Normal file
@ -0,0 +1,53 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-30 16:53
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='MockupProject',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255, verbose_name='Título do Projeto')),
|
||||
('main_image', models.ImageField(upload_to='mockups/uploads/', verbose_name='Imagem Principal')),
|
||||
('complementary_image_1', models.ImageField(blank=True, null=True, upload_to='mockups/uploads/')),
|
||||
('complementary_image_2', models.ImageField(blank=True, null=True, upload_to='mockups/uploads/')),
|
||||
('gender', models.CharField(choices=[('M', 'Masculino'), ('F', 'Feminino'), ('N', 'Não-binário')], default='F', max_length=1, verbose_name='Gênero')),
|
||||
('skin_tone', models.CharField(choices=[('light', 'Claro'), ('medium', 'Médio'), ('dark', 'Escuro')], default='medium', max_length=20, verbose_name='Tom de Pele')),
|
||||
('age', models.IntegerField(default=25, verbose_name='Idade')),
|
||||
('body_type', models.CharField(choices=[('plus', 'Plus-size'), ('slim', 'Magro'), ('athletic', 'Atlético'), ('muscular', 'Musculoso')], default='athletic', max_length=20, verbose_name='Tipo de Corpo')),
|
||||
('format', models.CharField(choices=[('9:16', '9:16 (Vertical)'), ('16:9', '16:9 (Horizontal)')], default='9:16', max_length=5, verbose_name='Formato')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('status', models.CharField(default='pending', max_length=20)),
|
||||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Projeto de Mockup',
|
||||
'verbose_name_plural': 'Projetos de Mockup',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='MockupResult',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('image', models.ImageField(upload_to='mockups/results/')),
|
||||
('view_type', models.CharField(max_length=10)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='results', to='core.mockupproject')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Resultado do Mockup',
|
||||
'verbose_name_plural': 'Resultados dos Mockups',
|
||||
},
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
@ -1,3 +1,56 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# Create your models here.
|
||||
class MockupProject(models.Model):
|
||||
GENDER_CHOICES = [
|
||||
('M', 'Masculino'),
|
||||
('F', 'Feminino'),
|
||||
('N', 'Não-binário'),
|
||||
]
|
||||
SKIN_TONE_CHOICES = [
|
||||
('light', 'Claro'),
|
||||
('medium', 'Médio'),
|
||||
('dark', 'Escuro'),
|
||||
]
|
||||
BODY_TYPE_CHOICES = [
|
||||
('plus', 'Plus-size'),
|
||||
('slim', 'Magro'),
|
||||
('athletic', 'Atlético'),
|
||||
('muscular', 'Musculoso'),
|
||||
]
|
||||
FORMAT_CHOICES = [
|
||||
('9:16', '9:16 (Vertical)'),
|
||||
('16:9', '16:9 (Horizontal)'),
|
||||
]
|
||||
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
|
||||
title = models.CharField(max_length=255, verbose_name="Título do Projeto")
|
||||
main_image = models.ImageField(upload_to='mockups/uploads/', verbose_name="Imagem Principal")
|
||||
complementary_image_1 = models.ImageField(upload_to='mockups/uploads/', null=True, blank=True)
|
||||
complementary_image_2 = models.ImageField(upload_to='mockups/uploads/', null=True, blank=True)
|
||||
|
||||
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, default='F', verbose_name="Gênero")
|
||||
skin_tone = models.CharField(max_length=20, choices=SKIN_TONE_CHOICES, default='medium', verbose_name="Tom de Pele")
|
||||
age = models.IntegerField(default=25, verbose_name="Idade")
|
||||
body_type = models.CharField(max_length=20, choices=BODY_TYPE_CHOICES, default='athletic', verbose_name="Tipo de Corpo")
|
||||
format = models.CharField(max_length=5, choices=FORMAT_CHOICES, default='9:16', verbose_name="Formato")
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
status = models.CharField(max_length=20, default='pending')
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Projeto de Mockup"
|
||||
verbose_name_plural = "Projetos de Mockup"
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class MockupResult(models.Model):
|
||||
project = models.ForeignKey(MockupProject, on_delete=models.CASCADE, related_name='results')
|
||||
image = models.ImageField(upload_to='mockups/results/')
|
||||
view_type = models.CharField(max_length=10) # front, side, back
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Resultado do Mockup"
|
||||
verbose_name_plural = "Resultados dos Mockups"
|
||||
@ -1,25 +1,122 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="pt-br">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Knowledge Base{% endblock %}</title>
|
||||
{% if project_description %}
|
||||
<meta name="description" content="{{ project_description }}">
|
||||
<meta property="og:description" content="{{ project_description }}">
|
||||
<meta property="twitter:description" content="{{ project_description }}">
|
||||
{% endif %}
|
||||
{% if project_image_url %}
|
||||
<meta property="og:image" content="{{ project_image_url }}">
|
||||
<meta property="twitter:image" content="{{ project_image_url }}">
|
||||
{% endif %}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}FashionMock AI{% endblock %}</title>
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=Playfair+Display:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Bootstrap 5 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--primary-dark: #121212;
|
||||
--accent-blue: #2962FF;
|
||||
--pearl-white: #F8F9FA;
|
||||
--soft-gray: #E0E0E0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: var(--pearl-white);
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
h1, h2, h3, .brand-font {
|
||||
font-family: 'Playfair Display', serif;
|
||||
}
|
||||
|
||||
.navbar-fashion {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.btn-fashion {
|
||||
background-color: var(--primary-dark);
|
||||
color: white;
|
||||
border-radius: 0;
|
||||
padding: 12px 30px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.btn-fashion:hover {
|
||||
background-color: var(--accent-blue);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.glass-card {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.07);
|
||||
}
|
||||
</style>
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block content %}{% endblock %}
|
||||
<nav class="navbar navbar-expand-lg navbar-fashion sticky-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand brand-font fw-bold fs-3" href="{% url 'index' %}">FashionMock AI</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto align-items-center">
|
||||
<li class="nav-nav-item mx-2">
|
||||
<a class="nav-link" href="{% url 'index' %}">Início</a>
|
||||
</li>
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item mx-2">
|
||||
<a class="nav-link" href="{% url 'dashboard' %}">Meus Mockups</a>
|
||||
</li>
|
||||
<li class="nav-item mx-2">
|
||||
<a class="btn btn-fashion btn-sm" href="{% url 'create_mockup' %}">Criar Novo</a>
|
||||
</li>
|
||||
<li class="nav-item mx-2">
|
||||
<form action="{% url 'logout' %}" method="post" class="d-inline">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-link nav-link">Sair</button>
|
||||
</form>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item mx-2">
|
||||
<a class="nav-link" href="{% url 'login' %}">Entrar</a>
|
||||
</li>
|
||||
<li class="nav-item mx-2">
|
||||
<a class="btn btn-fashion btn-sm" href="{% url 'login' %}">Começar Agora</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="py-5 bg-white border-top mt-5">
|
||||
<div class="container text-center">
|
||||
<p class="brand-font fs-4 fw-bold">FashionMock AI</p>
|
||||
<p class="text-muted small">© 2026 FashionMock AI. Criado para designers de moda modernos.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
132
core/templates/core/create_mockup.html
Normal file
132
core/templates/core/create_mockup.html
Normal file
@ -0,0 +1,132 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<section class="py-5">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="glass-card p-4 p-md-5 rounded-0">
|
||||
<h2 class="brand-font fw-bold mb-4 border-bottom pb-3">Novo Projeto de Mockup</h2>
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row g-4">
|
||||
<!-- Left Column: Uploads -->
|
||||
<div class="col-md-6">
|
||||
<h4 class="h5 mb-3 fw-bold">1. Upload das Fotos</h4>
|
||||
<div class="mb-4">
|
||||
<label for="title" class="form-label small text-uppercase fw-bold">Título do Projeto</label>
|
||||
<input type="text" class="form-control rounded-0" id="title" name="title" placeholder="Ex: Camiseta Oversized Verão 26" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label small text-uppercase fw-bold">Imagem Principal (Frente)</label>
|
||||
<div class="upload-box p-5 border border-dashed text-center bg-light" style="border: 2px dashed #ccc; cursor: pointer;">
|
||||
<input type="file" name="main_image" class="d-none" id="main_image_input" accept="image/*" required>
|
||||
<div id="upload_label">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-camera mb-2" viewBox="0 0 16 16">
|
||||
<path d="M15 12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1.172a3 3 0 0 0 2.12-.879l.83-.828A1 1 0 0 1 6.827 3h2.344a1 1 0 0 1 .707.293l.828.828A3 3 0 0 0 12.828 5H14a1 1 0 0 1 1 1v6zM2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2z"/>
|
||||
<path d="M8 11a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5zm0 1a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7zM3 6.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/>
|
||||
</svg>
|
||||
<p class="mb-0">Clique para selecionar foto</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold">Complemento 1</label>
|
||||
<input type="file" name="complementary_image_1" class="form-control rounded-0 form-control-sm">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold">Complemento 2</label>
|
||||
<input type="file" name="complementary_image_2" class="form-control rounded-0 form-control-sm">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Column: Settings -->
|
||||
<div class="col-md-6">
|
||||
<h4 class="h5 mb-3 fw-bold">2. Customização do Modelo</h4>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-uppercase fw-bold">Gênero</label>
|
||||
<select name="gender" class="form-select rounded-0">
|
||||
<option value="F">Feminino</option>
|
||||
<option value="M">Masculino</option>
|
||||
<option value="N">Não-binário</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-uppercase fw-bold">Tom de Pele</label>
|
||||
<div class="d-flex gap-2">
|
||||
<input type="radio" class="btn-check" name="skin_tone" id="skin_light" value="light" autocomplete="off">
|
||||
<label class="btn btn-outline-dark rounded-0 px-3" for="skin_light">Claro</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="skin_tone" id="skin_medium" value="medium" autocomplete="off" checked>
|
||||
<label class="btn btn-outline-dark rounded-0 px-3" for="skin_medium">Médio</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="skin_tone" id="skin_dark" value="dark" autocomplete="off">
|
||||
<label class="btn btn-outline-dark rounded-0 px-3" for="skin_dark">Escuro</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-uppercase fw-bold">Idade: <span id="age_val">25</span> anos</label>
|
||||
<input type="range" name="age" class="form-range" min="18" max="65" step="1" value="25" id="age_range">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-uppercase fw-bold">Biotipo</label>
|
||||
<select name="body_type" class="form-select rounded-0">
|
||||
<option value="athletic">Atlético</option>
|
||||
<option value="slim">Magro</option>
|
||||
<option value="plus">Plus-size</option>
|
||||
<option value="muscular">Musculoso</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label small text-uppercase fw-bold">Formato de Saída</label>
|
||||
<div class="d-flex gap-2">
|
||||
<input type="radio" class="btn-check" name="format" id="f916" value="9:16" autocomplete="off" checked>
|
||||
<label class="btn btn-outline-dark rounded-0 flex-fill py-3" for="f916">9:16 (Stories/Reels)</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="format" id="f169" value="16:9" autocomplete="off">
|
||||
<label class="btn btn-outline-dark rounded-0 flex-fill py-3" for="f169">16:9 (Feed/Site)</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-fashion w-100 py-3">GERAR MOCKUPS</button>
|
||||
<p class="text-center mt-3 small text-muted">A geração leva aprox. 1-2 minutos.</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
document.getElementById('age_range').addEventListener('input', function(e) {
|
||||
document.getElementById('age_val').textContent = e.target.value;
|
||||
});
|
||||
|
||||
const uploadBox = document.querySelector('.upload-box');
|
||||
const fileInput = document.getElementById('main_image_input');
|
||||
|
||||
uploadBox.addEventListener('click', () => fileInput.click());
|
||||
|
||||
fileInput.addEventListener('change', function(e) {
|
||||
if (this.files && this.files[0]) {
|
||||
document.getElementById('upload_label').innerHTML = `<p class='mb-0 fw-bold'>Arquivo selecionado:</p><small>${this.files[0].name}</small>`;
|
||||
uploadBox.style.borderColor = 'var(--accent-blue)';
|
||||
uploadBox.style.backgroundColor = 'rgba(41, 98, 255, 0.05)';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
48
core/templates/core/dashboard.html
Normal file
48
core/templates/core/dashboard.html
Normal file
@ -0,0 +1,48 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<section class="py-5">
|
||||
<div class="container">
|
||||
<div class="d-flex justify-content-between align-items-center mb-5">
|
||||
<h2 class="brand-font fw-bold mb-0">Meus Mockups</h2>
|
||||
<a href="{% url 'create_mockup' %}" class="btn btn-fashion">Novo Projeto</a>
|
||||
</div>
|
||||
|
||||
{% if projects %}
|
||||
<div class="row g-4">
|
||||
{% for project in projects %}
|
||||
<div class="col-md-4 col-lg-3">
|
||||
<div class="glass-card h-100 rounded-0 overflow-hidden">
|
||||
<div class="position-relative" style="padding-top: 125%; overflow: hidden;">
|
||||
<img src="{{ project.main_image.url }}" class="position-absolute top-0 start-0 w-100 h-100 object-fit-cover" alt="{{ project.title }}">
|
||||
<div class="position-absolute top-0 end-0 m-2">
|
||||
<span class="badge {% if project.status == 'pending' %}bg-warning{% elif project.status == 'completed' %}bg-success{% else %}bg-secondary{% endif %} rounded-0">
|
||||
{{ project.status|capfirst }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<h5 class="fw-bold text-truncate mb-1">{{ project.title }}</h5>
|
||||
<p class="text-muted small mb-3">{{ project.created_at|date:"d/m/Y H:i" }}</p>
|
||||
<a href="{% url 'project_detail' project.pk %}" class="btn btn-outline-dark btn-sm w-100 rounded-0">Ver Detalhes</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5 glass-card">
|
||||
<div class="py-5">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" fill="currentColor" class="bi bi-images text-muted mb-4" viewBox="0 0 16 16">
|
||||
<path d="M4.502 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/>
|
||||
<path d="M14.002 13a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2V5A2 2 0 0 1 2.002 3a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2zM14 2a1 1 0 0 0-1-1h-10a1 1 0 0 0-1 1v8l2.646-2.354a.5.5 0 0 1 .63-.062l2.66 1.773 3.71-3.71a.5.5 0 0 1 .706 0L14 9.293V2z"/>
|
||||
</svg>
|
||||
<h3 class="fw-bold">Nenhum projeto ainda</h3>
|
||||
<p class="text-muted mb-4">Comece enviando sua primeira peça de roupa.</p>
|
||||
<a href="{% url 'create_mockup' %}" class="btn btn-fashion btn-lg">CRIAR MEU PRIMEIRO MOCKUP</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
@ -1,145 +1,88 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ project_name }}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'><path d='M-10 10L110 10M10 -10L10 110' stroke-width='1' stroke='rgba(255,255,255,0.05)'/></svg>");
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@keyframes bg-pan {
|
||||
0% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2.5rem 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.2rem, 3vw + 1.2rem, 3.2rem);
|
||||
font-weight: 700;
|
||||
margin: 0 0 1.2rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.loader {
|
||||
margin: 1.5rem auto;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.runtime code {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
padding: 0.15rem 0.45rem;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.75;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your app…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
<!-- Hero Section -->
|
||||
<section class="hero-section py-5 d-flex align-items-center" style="min-height: 80vh; background: linear-gradient(135deg, #F8F9FA 0%, #E9ECEF 100%);">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6">
|
||||
<span class="badge bg-fashion mb-3 px-3 py-2 text-uppercase ls-1" style="background-color: var(--accent-blue);">SaaS de Moda AI</span>
|
||||
<h1 class="display-3 fw-bold mb-4">Transforme suas peças em <span class="fst-italic">mockups reais</span> em minutos.</h1>
|
||||
<p class="lead mb-5 text-muted">Crie fotos profissionais para seu catálogo e redes sociais sem precisar de modelos ou estúdios caros. Tecnologia AI de alta fidelidade para o mercado brasileiro.</p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="{% url 'create_mockup' %}" class="btn btn-fashion btn-lg">Começar Agora</a>
|
||||
<a href="#features" class="btn btn-outline-dark btn-lg border-2" style="border-radius: 0;">Ver Exemplos</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mt-5 mt-lg-0">
|
||||
<div class="position-relative">
|
||||
<div class="glass-card p-4 rounded-0 shadow-lg">
|
||||
<img src="https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80" class="img-fluid" alt="Fashion Mockup Example">
|
||||
<div class="position-absolute bottom-0 start-0 m-4 p-3 bg-white shadow-sm border-start border-primary border-4">
|
||||
<p class="mb-0 fw-bold">Gerado por AI</p>
|
||||
<small class="text-muted">Modelo: Feminino, 25 anos, Atlético</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="hint">AppWizzy AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will refresh automatically as the plan is implemented.</p>
|
||||
<p class="runtime">
|
||||
Runtime: Django <code>{{ django_version }}</code> · Python <code>{{ python_version }}</code>
|
||||
— UTC <code>{{ current_time|date:"Y-m-d H:i:s" }}</code>
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC)
|
||||
</footer>
|
||||
{% endblock %}
|
||||
</section>
|
||||
|
||||
<!-- Features Section -->
|
||||
<section id="features" class="py-5 bg-white">
|
||||
<div class="container">
|
||||
<div class="text-center mb-5">
|
||||
<h2 class="display-5 fw-bold mb-3">Como Funciona</h2>
|
||||
<p class="text-muted">Simples, rápido e ultra-realista.</p>
|
||||
</div>
|
||||
<div class="row g-4 text-center">
|
||||
<div class="col-md-4">
|
||||
<div class="p-4">
|
||||
<div class="mb-4 d-inline-block p-3 bg-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-cloud-upload" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" d="M4.406 1.342A5.53 5.53 0 0 1 8 0c2.69 0 4.923 2 5.166 4.579C14.758 4.804 16 6.137 16 7.773 16 9.569 14.502 11 12.687 11H10a.5.5 0 0 1 0-1h2.688C13.979 10 15 8.988 15 7.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 2.825 10.328 1 8 1a4.53 4.53 0 0 0-2.941 1.1c-.757.652-1.153 1.438-1.153 2.055v.448l-.445.049C2.064 4.805 1 5.952 1 7.318 1 8.785 2.23 10 3.781 10H6a.5.5 0 0 1 0 1H3.781C1.708 11 0 9.366 0 7.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383z"/>
|
||||
<path fill-rule="evenodd" d="M7.646 4.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V14.5a.5.5 0 0 1-1 0V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="h4 mb-3">1. Upload</h3>
|
||||
<p class="text-muted">Suba as fotos das suas peças reais. Sem truques, apenas a sua criação.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="p-4">
|
||||
<div class="mb-4 d-inline-block p-3 bg-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-person-gear" viewBox="0 0 16 16">
|
||||
<path d="M11 5a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM8 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm.256 7a4.474 4.474 0 0 1-.229-1.004H3c.001-.246.154-.986.832-1.664C4.484 10.68 5.711 10 8 10c.26 0 .507.009.74.025.226-.341.496-.65.804-.918C9.077 9.038 8.564 9 8 9c-5 0-6 3-6 4s1 1 1 1h5.256Zm3.637-1.401.568.094a1.095 1.095 0 0 0 1.178-.71l.241-.734a1.096 1.096 0 0 0-.49-1.287l-.46-.285a1.108 1.108 0 0 0-1.358.118l-.406.337a1.094 1.094 0 0 1-1.319.102l-.317-.184a1.1 1.1 0 0 0-1.296.11l-.427.354a1.094 1.094 0 0 0-.27 1.344l.205.518c.113.284.09.601-.063.867l-.234.408a1.1 1.1 0 0 0 .157 1.316l.41.432c.311.33.82.4 1.21.162l.462-.285a1.109 1.109 0 0 1 1.315.012l.422.306c.35.253.84.223 1.155-.072l.413-.39c.315-.297.357-.79.102-1.134l-.274-.368a1.094 1.094 0 0 1-.036-1.289Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="h4 mb-3">2. Customize</h3>
|
||||
<p class="text-muted">Escolha o modelo, idade, tom de pele e biotipo que melhor representa sua marca.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="p-4">
|
||||
<div class="mb-4 d-inline-block p-3 bg-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-images" viewBox="0 0 16 16">
|
||||
<path d="M4.502 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/>
|
||||
<path d="M14.002 13a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2V5A2 2 0 0 1 2.002 3a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2zM14 2a1 1 0 0 0-1-1h-10a1 1 0 0 0-1 1v8l2.646-2.354a.5.5 0 0 1 .63-.062l2.66 1.773 3.71-3.71a.5.5 0 0 1 .706 0L14 9.293V2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="h4 mb-3">3. Gere e Baixe</h3>
|
||||
<p class="text-muted">Em minutos, receba 3 mockups (frente, lado e costas) prontos para uso em HD.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section class="py-5 bg-dark text-white">
|
||||
<div class="container text-center py-4">
|
||||
<h2 class="display-6 fw-bold mb-4 brand-font">Pronto para elevar sua marca?</h2>
|
||||
<p class="mb-5 opacity-75">Junte-se a centenas de marcas brasileiras que já usam FashionMock AI.</p>
|
||||
<a href="{% url 'create_mockup' %}" class="btn btn-light btn-lg border-0 px-5" style="border-radius: 0; color: black; font-weight: 600;">CRIAR MEU PRIMEIRO MOCKUP</a>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
45
core/templates/core/login.html
Normal file
45
core/templates/core/login.html
Normal file
@ -0,0 +1,45 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<section class="py-5 d-flex align-items-center" style="min-height: 80vh;">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-5">
|
||||
<div class="glass-card p-4 p-md-5 rounded-0">
|
||||
<div class="text-center mb-5">
|
||||
<h2 class="brand-font fw-bold mb-3">Bem-vindo</h2>
|
||||
<p class="text-muted">Entre na sua conta FashionMock AI</p>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="mb-3">
|
||||
<label for="id_username" class="form-label small text-uppercase fw-bold">Usuário</label>
|
||||
<input type="text" name="username" class="form-control rounded-0" id="id_username" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="id_password" class="form-label small text-uppercase fw-bold">Senha</label>
|
||||
<input type="password" name="password" class="form-control rounded-0" id="id_password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-fashion w-100 py-3 mb-3">ENTRAR</button>
|
||||
|
||||
<div class="text-center">
|
||||
<a href="#" class="text-muted small">Esqueceu a senha?</a>
|
||||
<hr class="my-4">
|
||||
<p class="small text-muted">Ainda não tem conta? <a href="#" class="text-dark fw-bold">Crie uma agora</a></p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="mt-4">
|
||||
<button class="btn btn-outline-dark w-100 rounded-0 d-flex align-items-center justify-content-center gap-2 py-2">
|
||||
<img src="https://www.google.com/favicon.ico" width="16" height="16" alt="Google">
|
||||
Continuar com Google
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
85
core/templates/core/project_detail.html
Normal file
85
core/templates/core/project_detail.html
Normal file
@ -0,0 +1,85 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<section class="py-5">
|
||||
<div class="container">
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{% url 'dashboard' %}" class="text-dark">Dashboard</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ project.title }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row g-5">
|
||||
<div class="col-lg-4">
|
||||
<div class="glass-card p-4 rounded-0">
|
||||
<h4 class="fw-bold mb-4 border-bottom pb-2">Detalhes do Projeto</h4>
|
||||
<img src="{{ project.main_image.url }}" class="img-fluid mb-4 border" alt="Original">
|
||||
|
||||
<div class="mb-3">
|
||||
<span class="small text-uppercase text-muted d-block">Status</span>
|
||||
<span class="fw-bold">{% if project.status == 'pending' %}Aguardando Processamento{% else %}{{ project.status|capfirst }}{% endif %}</span>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<span class="small text-uppercase text-muted d-block">Modelo</span>
|
||||
<p class="mb-0">
|
||||
Gênero: {{ project.get_gender_display }}<br>
|
||||
Tom de Pele: {{ project.get_skin_tone_display }}<br>
|
||||
Idade: {{ project.age }} anos<br>
|
||||
Biotipo: {{ project.get_body_type_display }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<span class="small text-uppercase text-muted d-block">Formato</span>
|
||||
<span class="fw-bold">{{ project.format }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-8">
|
||||
<div class="glass-card p-4 p-md-5 rounded-0 h-100">
|
||||
<h3 class="brand-font fw-bold mb-4">Resultados Gerados</h3>
|
||||
|
||||
{% if project.results.all %}
|
||||
<div class="row g-4">
|
||||
{% for result in project.results.all %}
|
||||
<div class="col-md-6">
|
||||
<div class="border p-2">
|
||||
<img src="{{ result.image.url }}" class="img-fluid" alt="{{ result.view_type }}">
|
||||
<div class="d-flex justify-content-between align-items-center mt-2">
|
||||
<span class="small text-uppercase fw-bold">{{ result.view_type|capfirst }}</span>
|
||||
<a href="{{ result.image.url }}" download class="btn btn-sm btn-link text-dark">Baixar</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<div class="spinner-border text-dark mb-4" role="status" style="width: 3rem; height: 3rem;">
|
||||
<span class="visually-hidden">Processando...</span>
|
||||
</div>
|
||||
<h4 class="fw-bold">Sua mágica está sendo preparada...</h4>
|
||||
<p class="text-muted">Nossa AI está vestindo os modelos e ajustando a iluminação. Isso levará cerca de 60 segundos.</p>
|
||||
<div class="progress mt-4 rounded-0" style="height: 10px;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated bg-dark" role="progressbar" style="width: 45%"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% if project.status == 'pending' %}
|
||||
<script>
|
||||
// Simple auto-refresh mock for demo purposes
|
||||
setTimeout(function() {
|
||||
// location.reload();
|
||||
}, 10000);
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
15
core/urls.py
15
core/urls.py
@ -1,7 +1,14 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import home
|
||||
from . import views
|
||||
from django.contrib.auth import views as auth_views
|
||||
|
||||
urlpatterns = [
|
||||
path("", home, name="home"),
|
||||
]
|
||||
path("", views.home, name="index"),
|
||||
path("dashboard/", views.dashboard, name="dashboard"),
|
||||
path("criar/", views.create_mockup, name="create_mockup"),
|
||||
path("projeto/<int:pk>/", views.project_detail, name="project_detail"),
|
||||
|
||||
# Auth
|
||||
path("login/", auth_views.LoginView.as_view(template_name="core/login.html"), name="login"),
|
||||
path("logout/", auth_views.LogoutView.as_view(next_page="index"), name="logout"),
|
||||
]
|
||||
@ -1,25 +1,37 @@
|
||||
import os
|
||||
import platform
|
||||
|
||||
from django import get_version as django_version
|
||||
from django.shortcuts import render
|
||||
from django.utils import timezone
|
||||
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from .models import MockupProject, MockupResult
|
||||
|
||||
def home(request):
|
||||
"""Render the landing screen with loader and environment details."""
|
||||
host_name = request.get_host().lower()
|
||||
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
|
||||
now = timezone.now()
|
||||
"""Polished landing page for FashionMock AI."""
|
||||
return render(request, "core/index.html")
|
||||
|
||||
context = {
|
||||
"project_name": "New Style",
|
||||
"agent_brand": agent_brand,
|
||||
"django_version": django_version(),
|
||||
"python_version": platform.python_version(),
|
||||
"current_time": now,
|
||||
"host_name": host_name,
|
||||
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
|
||||
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
|
||||
}
|
||||
return render(request, "core/index.html", context)
|
||||
@login_required
|
||||
def dashboard(request):
|
||||
"""User dashboard showing project history."""
|
||||
projects = MockupProject.objects.filter(user=request.user).order_by('-created_at')
|
||||
return render(request, "core/dashboard.html", {"projects": projects})
|
||||
|
||||
@login_required
|
||||
def create_mockup(request):
|
||||
"""Workflow to create a new fashion mockup."""
|
||||
if request.method == "POST":
|
||||
project = MockupProject.objects.create(
|
||||
user=request.user,
|
||||
title=request.POST.get("title", "Novo Projeto"),
|
||||
main_image=request.FILES.get("main_image"),
|
||||
gender=request.POST.get("gender", "F"),
|
||||
skin_tone=request.POST.get("skin_tone", "medium"),
|
||||
age=request.POST.get("age", 25),
|
||||
body_type=request.POST.get("body_type", "athletic"),
|
||||
format=request.POST.get("format", "9:16")
|
||||
)
|
||||
return redirect('dashboard')
|
||||
|
||||
return render(request, "core/create_mockup.html")
|
||||
|
||||
def project_detail(request, pk):
|
||||
"""View details and results of a mockup project."""
|
||||
project = MockupProject.objects.get(pk=pk)
|
||||
return render(request, "core/project_detail.html", {"project": project})
|
||||
Loading…
x
Reference in New Issue
Block a user