html
Briefing de Gestão de Mídias Sociais - VIX
/* Variáveis de Cores */
:root {
--primary-color: #007BFF; /* Azul */
--secondary-color: #d7c3a8; /* Bege/Terroso */
--accent-color: #3b412c; /* Verde Escuro */
--bg-light: #f8f9fa; /* Fundo claro */
--card-bg-gradient: linear-gradient(145deg, #ffffff, #f0f0f0); /* Degradê suave para cards */
--shadow-light: rgba(0, 0, 0, 0.05); /* Sombra suave */
--text-muted: #6c757d; /* Texto dica */
}
body {
font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
background-color: var(--bg-light);
display: flex;
justify-content: center;
align-items: flex-start; /* Alinha ao topo */
min-height: 100vh;
padding: 20px 0;
}
.form-container {
max-width: 900px;
width: 100%;
background-color: #fff;
border-radius: 15px;
box-shadow: 0 10px 30px var(--shadow-light);
padding: 30px;
margin-top: 20px; /* Espaço do topo */
}
.logo-header {
max-height: 60px;
margin-bottom: 25px;
display: block;
margin-left: auto;
margin-right: auto;
}
h2.form-title {
color: var(--accent-color);
font-weight: 700;
text-align: center;
margin-bottom: 30px;
}
/* Estilos do Stepper */
.stepper-wrapper {
display: flex;
justify-content: space-between;
margin-bottom: 40px;
position: relative;
padding: 0 10px;
}
.stepper-wrapper::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 2px;
background-color: #e0e0e0;
transform: translateY(-50%);
z-index: 0;
}
.stepper-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
position: relative;
z-index: 1;
cursor: pointer;
transition: all 0.3s ease;
}
.stepper-item.completed .step-counter {
background-color: var(--primary-color); /* Cor de fundo para passos completos */
color: #fff;
}
.stepper-item.completed .step-counter i {
color: #fff;
}
.stepper-item.active .step-counter {
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}
.stepper-item.active .step-name {
color: var(--primary-color);
font-weight: 600;
}
.step-counter {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #fff;
border: 2px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 8px;
font-size: 18px;
color: #ccc;
transition: all 0.3s ease;
}
.step-counter i {
color: #ccc;
transition: all 0.3s ease;
}
.step-name {
font-size: 13px;
text-align: center;
color: #888;
transition: all 0.3s ease;
}
/* Cores específicas dos ícones do stepper */
.stepper-item[data-step="1"] .step-counter i { color: #007BFF; }
.stepper-item[data-step="2"] .step-counter i { color: #17A2B8; }
.stepper-item[data-step="3"] .step-counter i { color: #28A745; }
.stepper-item[data-step="4"] .step-counter i { color: #FFC107; }
.stepper-item[data-step="5"] .step-counter i { color: #E83E8C; }
.stepper-item[data-step="6"] .step-counter i { color: #6F42C1; }
/* Cores de fundo dos ícones do stepper quando completos */
.stepper-item.completed[data-step="1"] .step-counter { background-color: #007BFF; }
.stepper-item.completed[data-step="2"] .step-counter { background-color: #17A2B8; }
.stepper-item.completed[data-step="3"] .step-counter { background-color: #28A745; }
.stepper-item.completed[data-step="4"] .step-counter { background-color: #FFC107; }
.stepper-item.completed[data-step="5"] .step-counter { background-color: #E83E8C; }
.stepper-item.completed[data-step="6"] .step-counter { background-color: #6F42C1; }
/* Cores dos ícones do stepper quando completos (branco) */
.stepper-item.completed .step-counter i { color: #fff !important; }
/* Barra de Progresso */
.progress {
height: 8px;
margin-bottom: 30px;
border-radius: 5px;
background-color: #e9ecef;
}
.progress-bar {
background-color: var(--primary-color);
border-radius: 5px;
transition: width 0.5s ease-in-out;
}
/* Passos do Formulário */
.form-step {
display: none;
animation: fadeIn 0.5s ease-out;
}
.form-step.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.card-custom {
background: var(--card-bg-gradient);
border: none;
border-radius: 10px;
box-shadow: 0 5px 15px var(--shadow-light);
padding: 25px;
margin-bottom: 25px;
}
.form-label {
font-weight: 600;
color: var(--accent-color);
margin-bottom: 8px;
}
.form-control, .form-select {
border-radius: 8px;
border: 1px solid #ced4da;
padding: 10px 15px;
transition: all 0.3s ease;
}
.form-control:focus, .form-select:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(0, 123, 255, 0.25);
}
.form-control::placeholder {
color: #adb5bd;
font-style: italic;
}
.form-text {
font-size: 0.85em;
color: var(--text-muted);
margin-top: 5px;
}
/* Botões */
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-color);
border-radius: 8px;
padding: 10px 25px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-primary:hover {
background-color: #0056b3;
border-color: #0056b3;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 123, 255, 0.2);
}
.btn-secondary {
background-color: var(--secondary-color);
border-color: var(--secondary-color);
color: var(--accent-color);
border-radius: 8px;
padding: 10px 25px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-secondary:hover {
background-color: #c0b09a;
border-color: #c0b09a;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(215, 195, 168, 0.3);
}
.form-check-input:checked {
background-color: var(--primary-color);
border-color: var(--primary-color);
}
.form-check-label i {
margin-right: 8px;
color: var(--primary-color); /* Cor padrão para ícones de checkboxes */
}
/* Ajustes Responsivos */
@media (max-width: 768px) {
.stepper-wrapper {
flex-wrap: wrap;
justify-content: center;
}
.stepper-item {
flex: none;
width: 33%; /* 3 itens por linha */
margin-bottom: 20px;
}
.stepper-wrapper::before {
display: none; /* Esconde a linha em telas pequenas */
}
.form-container {
padding: 20px;
margin-top: 10px;
}
.logo-header {
max-height: 50px;
}
}
@media (max-width: 576px) {
.stepper-item {
width: 50%; /* 2 itens por linha */
}
.stepper-item .step-name {
font-size: 11px;
}
.step-counter {
width: 35px;
height: 35px;
font-size: 16px;
}
}
Briefing de Gestão de Mídias Sociais
Identificação
Cliente
Empresa
Concorrência
Público-Alvo
Projeto
Identificação
Responsável pelo Briefing
Por favor, preencha o nome do responsável.
Data
Preenchida automaticamente com a data de hoje
Próximo
Cliente
Nome da Empresa
Por favor, preencha o nome da empresa.
Produto/Serviço Principal
Por favor, preencha o produto/serviço principal.
Responsável pela Empresa
Por favor, preencha o responsável pela empresa.
Email
Por favor, preencha um email válido.
Telefone
Por favor, preencha um telefone válido.
Anterior
Próximo
Empresa
Breve Histórico
Por favor, preencha o histórico da empresa.
Produtos/Serviços
Por favor, descreva os produtos/serviços.
Site
Por favor, preencha um URL de site válido.
Redes Sociais Atuais
Por favor, liste as redes sociais atuais.
Preços no Mercado
Por favor, descreva os preços no mercado.
Distribuição
Por favor, descreva a distribuição da empresa.
Anterior
Próximo
Concorrência
Principais Concorrentes
Por favor, liste os principais concorrentes.
Preço/Distribuição dos Concorrentes
Por favor, descreva a estratégia de preço/distribuição dos concorrentes.
Pontos Fortes e Fracos dos Concorrentes
Por favor, descreva os pontos fortes e fracos dos concorrentes.
Anterior
Próximo
Público-Alvo
Persona
Por favor, descreva a persona.
Hábitos e Comportamentos
Por favor, descreva os hábitos e comportamentos do público-alvo.
Razões de Aquisição
Por favor, descreva as razões de aquisição.
Anterior
Próximo
Projeto
Redes Sociais a Gerenciar
Facebook
Instagram
TikTok
LinkedIn
Twitter/X
YouTube
Outras
Por favor, especifique as outras redes sociais.
Objetivos Principais
Pode marcar mais de um objetivo
Vender produtos físicos
Vender cursos/serviços
Captar leads/orçamentos
Apresentar produtos/serviços
Distribuir conteúdo/educar
Mensagem Principal
Por favor, preencha a mensagem principal.
Tom de Voz
Como a empresa fala com seus clientes?
Corporativo
Didático
Moderno
Formal
Informal
Humor
Jovem/Descontraído
Por favor, selecione o tom de voz.
Problemas Atuais
Por favor, descreva os problemas atuais.
Vantagens Atuais
Por favor, descreva as vantagens atuais.
Postagens por Semana
Por favor, preencha o número de postagens por semana.
Verba para Anúncios (R$)
Por favor, preencha a verba para anúncios.
Lista de Referências
Por favor, liste pelo menos 3 perfis de referência.
Lista de Exclusão
Por favor, liste pelo menos 3 perfis de exclusão.
Adicionar Compra de Fotos/Vídeos
Por favor, descreva se deseja comprar fotos/vídeos.
Adicionar Produção de Fotos/Vídeos
Por favor, descreva se deseja produção de fotos/vídeos.
Prazo para Finalizar
Por favor, preencha o prazo para finalizar.
Anterior
Enviar Briefing
Fechar
Novo Briefing
const form = document.getElementById('briefingForm');
const formSteps = document.querySelectorAll('.form-step');
const stepperItems = document.querySelectorAll('.stepper-item');
const progressBar = document.querySelector('.progress-bar');
const prevButtons = document.querySelectorAll('.prev-step');
const nextButtons = document.querySelectorAll('.next-step');
const submitButton = document.getElementById('submitBtn');
const feedbackModal = new bootstrap.Modal(document.getElementById('feedbackModal'));
const feedbackModalLabel = document.getElementById('feedbackModalLabel');
const feedbackModalBody = document.getElementById('feedbackModalBody');
const resetFormBtn = document.getElementById('resetFormBtn');
const outrasRedesCheckbox = document.getElementById('redeOutras');
const outrasRedesContainer = document.getElementById('outrasRedesContainer');
const outrasRedesInput = document.getElementById('outrasRedes');
let currentStep = 0;
const totalSteps = formSteps.length;
// URL do Google Apps Script (SUBSTITUA PELA SUA ID DE IMPLANTAÇÃO REAL)
const SCRIPT_URL = 'https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec';
// --- Funções Auxiliares ---
function showStep(stepIndex) {
formSteps.forEach((step, index) => {
step.classList.toggle('active', index === stepIndex);
});
currentStep = stepIndex;
updateStepperUI();
}
function updateStepperUI() {
stepperItems.forEach((item, index) => {
item.classList.toggle('active', index === currentStep);
item.classList.toggle('completed', index < currentStep);
});
const progress = ((currentStep + 1) / totalSteps) * 100;
progressBar.style.width = `${progress}%`;
progressBar.setAttribute('aria-valuenow', progress);
}
function validateStep(stepIndex) {
const currentFormStep = formSteps[stepIndex];
let isValid = true;
const requiredInputs = currentFormStep.querySelectorAll('[required]');
requiredInputs.forEach(input => {
if (input.type === 'checkbox') {
// Para grupos de checkboxes, verifica se pelo menos um está marcado
const checkboxGroup = document.querySelectorAll(`input[name="${input.name}"]:checked`);
if (checkboxGroup.length === 0) {
isValid = false;
input.classList.add('is-invalid');
} else {
input.classList.remove('is-invalid');
}
} else if (input.type === 'radio') {
// Para grupos de radio buttons, verifica se pelo menos um está marcado
const radioGroup = document.querySelectorAll(`input[name="${input.name}"]:checked`);
if (radioGroup.length === 0) {
isValid = false;
input.classList.add('is-invalid');
} else {
input.classList.remove('is-invalid');
}
} else if (input.value.trim() === '') {
isValid = false;
input.classList.add('is-invalid');
} else {
input.classList.remove('is-invalid');
}
});
// Validação específica para "Outras Redes" se marcada
if (stepIndex === 5 && outrasRedesCheckbox.checked && outrasRedesInput.value.trim() === '') {
isValid = false;
outrasRedesInput.classList.add('is-invalid');
} else if (stepIndex === 5 && outrasRedesCheckbox.checked) {
outrasRedesInput.classList.remove('is-invalid');
}
return isValid;
}
function autoFillDate() {
const today = new Date();
const yyyy = today.getFullYear();
const mm = String(today.getMonth() + 1).padStart(2, '0'); // Meses começam em 0!
const dd = String(today.getDate()).padStart(2, '0');
document.getElementById('dataBriefing').value = `${yyyy}-${mm}-${dd}`;
}
function toggleOutrasRedesInput() {
if (outrasRedesCheckbox.checked) {
outrasRedesContainer.style.display = 'block';
outrasRedesInput.setAttribute('required', 'true');
} else {
outrasRedesContainer.style.display = 'none';
outrasRedesInput.removeAttribute('required');
outrasRedesInput.classList.remove('is-invalid'); // Limpa validação se escondido
outrasRedesInput.value = ''; // Limpa valor se escondido
}
}
// --- Listeners de Eventos ---
nextButtons.forEach(button => {
button.addEventListener('click', () => {
if (validateStep(currentStep)) {
if (currentStep < totalSteps - 1) {
showStep(currentStep + 1);
}
}
});
});
prevButtons.forEach(button => {
button.addEventListener('click', () => {
if (currentStep > 0) {
showStep(currentStep - 1);
}
});
});
stepperItems.forEach((item, index) => {
item.addEventListener('click', () => {
// Permite navegação direta apenas para passos anteriores ou o passo atual,
// ou para o próximo passo se o atual for validado.
if (index < currentStep || (index === currentStep) || (index === currentStep + 1 && validateStep(currentStep))) {
showStep(index);
}
});
});
outrasRedesCheckbox.addEventListener('change', toggleOutrasRedesInput);
form.addEventListener('submit', async (e) => {
e.preventDefault();
if (!validateStep(currentStep)) {
return;
}
submitButton.disabled = true;
submitButton.querySelector('.spinner-border').classList.remove('d-none');
submitButton.querySelector('i').classList.add('d-none');
const formData = new FormData(form);
const data = {};
for (let [key, value] of formData.entries()) {
// Lida com múltiplos checkboxes com o mesmo nome
if (key === 'Redes Sociais a Gerenciar' || key === 'Objetivos Principais') {
if (!data[key]) {
data[key] = [];
}
data[key].push(value);
} else {
data[key] = value;
}
}
// Adiciona timestamp
data['Data de Resposta'] = new Date().toLocaleString('pt-BR', { timeZone: 'America/Sao_Paulo' });
try {
const response = await fetch(SCRIPT_URL, {
method: 'POST',
mode: 'no-cors', // Necessário para Google Apps Script
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
// Como o modo 'no-cors' é usado, não podemos ler diretamente response.ok ou response.json()
// Assumimos sucesso se nenhum erro de rede ocorreu.
feedbackModalLabel.textContent = 'Sucesso!';
feedbackModalLabel.style.color = 'var(--primary-color)';
feedbackModalBody.innerHTML = '
Seu briefing foi enviado com sucesso! Agradecemos sua colaboração.
'; resetFormBtn.style.display = 'inline-block'; feedbackModal.show(); } catch (error) { console.error('Erro ao enviar o formulário:', error); feedbackModalLabel.textContent = 'Erro!'; feedbackModalLabel.style.color = '#dc3545'; feedbackModalBody.innerHTML = `Ocorreu um erro ao enviar seu briefing. Por favor, tente novamente mais tarde. Detalhes: ${error.message}
`; resetFormBtn.style.display = 'none'; feedbackModal.show(); } finally { submitButton.disabled = false; submitButton.querySelector('.spinner-border').classList.add('d-none'); submitButton.querySelector('i').classList.remove('d-none'); } }); resetFormBtn.addEventListener('click', () => { form.reset(); form.querySelectorAll('.is-invalid').forEach(el => el.classList.remove('is-invalid')); showStep(0); feedbackModal.hide(); toggleOutrasRedesInput(); // Reseta a visibilidade do input 'Outras Redes' autoFillDate(); // Preenche a data novamente }); // --- Configuração Inicial --- document.addEventListener('DOMContentLoaded', () => { autoFillDate(); showStep(0); // Mostra o primeiro passo toggleOutrasRedesInput(); // Inicializa a visibilidade do input 'Outras Redes' }); --- ### Código para Google Apps Script Este código deve ser colado no editor do Google Apps Script associado à sua planilha. ```javascript /** * Google Apps Script para receber dados de formulário via POST e gravar em uma planilha. * * INSTRUÇÕES: * 1. Crie uma nova planilha no Google Sheets (ex: "Briefings de Mídias Sociais VIX"). * 2. Abra o Google Apps Script: Na sua planilha, vá em "Extensões" > "Apps Script". * 3. Copie e cole este código no editor do Apps Script, substituindo qualquer código existente. * 4. Salve o projeto (ícone de disquete ou Ctrl+S/Cmd+S). Você pode dar um nome ao projeto. * 5. Implante o script como um aplicativo da web: * - Clique em "Implantar" (Deploy) > "Nova implantação" (New deployment). * - Selecione o tipo "Aplicativo da Web" (Web app). * - Configure: * - "Executar como": Seu e-mail (Eu) * - "Quem tem acesso": Qualquer pessoa (Anyone) * - Clique em "Implantar". * - Se solicitado, autorize o script (pode exigir que você clique em "Avançado" e depois "Ir para [Nome do Projeto] (não seguro)"). * 6. Copie o "URL do aplicativo da Web" (Web app URL) que será exibido após a implantação. * 7. Cole este URL no código HTML do formulário, substituindo 'https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec'. * 8. Teste o formulário no navegador. */ function doPost(e) { var sheetName = "Respostas Briefing"; // Nome da aba na sua planilha onde os dados serão salvos var ss = SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName(sheetName); // Se a aba não existir, crie-a if (!sheet) { sheet = ss.insertSheet(sheetName); } var data = JSON.parse(e.postData.contents); var headers = []; var rowData = []; // Obter cabeçalhos da primeira linha da planilha ou criar novos if (sheet.getLastRow() === 0) { // Se a planilha estiver vazia, crie os cabeçalhos com base nas chaves do JSON headers = Object.keys(data); sheet.appendRow(headers); } else { // Se já houver cabeçalhos, use-os headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0]; // Adiciona novos cabeçalhos se existirem no JSON e não na planilha Object.keys(data).forEach(function(key) { if (headers.indexOf(key) === -1) { headers.push(key); sheet.getRange(1, sheet.getLastColumn() + 1).setValue(key); // Adiciona o novo cabeçalho } }); } // Preencher os dados da linha na ordem dos cabeçalhos for (var i = 0; i < headers.length; i++) { var header = headers[i]; var value = data[header]; // Tratar arrays (checkboxes) para que sejam salvos como uma string separada por vírgulas if (Array.isArray(value)) { rowData.push(value.join(', ')); } else { rowData.push(value); } } sheet.appendRow(rowData); // Retornar uma resposta de sucesso (necessário para o fetch, mesmo em no-cors) return ContentService.createTextOutput(JSON.stringify({ 'result': 'success', 'message': 'Dados recebidos com sucesso!' })) .setMimeType(ContentService.MimeType.JSON); } ```