V1 Mockup ai

This commit is contained in:
Flatlogic Bot 2026-01-30 17:52:56 +00:00
parent 39e04707ed
commit feced6b0d6
20 changed files with 675 additions and 183 deletions

View File

@ -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'

View File

@ -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)

View File

@ -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')

View 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',
},
),
]

View File

@ -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"

View File

@ -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>

View 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 %}

View 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 %}

View File

@ -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 %}

View 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 %}

View 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 %}

View File

@ -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"),
]

View File

@ -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})