Files
dbmaker/estrutura_visual/exported-assets/exemplos-codigo-template.md

24 KiB

Exemplos de Código - Template Databook SteelBook

1. Estrutura HTML - Capa Frontal

<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Databook - Capa Frontal</title>
    <style>
        .cover-page {
            width: 210mm;
            height: 297mm;
            padding: 40mm 30mm;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            align-items: center;
            font-family: 'Roboto', Arial, sans-serif;
        }
        
        .cover-header {
            text-align: center;
        }
        
        .client-logo {
            width: 200px;
            height: 100px;
            object-fit: contain;
            margin-bottom: 30px;
        }
        
        .cover-title {
            font-size: 60px;
            font-weight: bold;
            color: #1a365d;
            line-height: 1.2;
            margin-bottom: 20px;
        }
        
        .cover-subtitle {
            font-size: 36px;
            color: #2d3748;
            margin-bottom: 40px;
        }
        
        .cover-separator {
            width: 60%;
            height: 3px;
            background: #2b6cb0;
            margin: 30px 0;
        }
        
        .cover-info {
            text-align: center;
            font-size: 24px;
            color: #4a5568;
        }
        
        .cover-info strong {
            color: #1a365d;
            display: block;
            margin-top: 15px;
        }
        
        .supplier-logo {
            width: 150px;
            height: 75px;
            object-fit: contain;
        }
    </style>
</head>
<body>
    <div class="cover-page">
        <div class="cover-header">
            <img src="{{client_logo}}" alt="Logo Cliente" class="client-logo">
            <h1 class="cover-title">{{project_title}}</h1>
            <h2 class="cover-subtitle">{{project_subtitle}}</h2>
            <div class="cover-separator"></div>
        </div>
        
        <div class="cover-info">
            <strong>Documento: {{document_number}}</strong>
            <strong>Contrato: {{contract_number}}</strong>
            <strong>Data: {{issue_date}}</strong>
        </div>
        
        <img src="{{supplier_logo}}" alt="Logo Fornecedor" class="supplier-logo">
    </div>
</body>
</html>

2. Estrutura HTML - Índice Geral

<div class="index-page">
    <h1 class="index-title">ÍNDICE / TABLE OF CONTENTS</h1>
    <div class="index-separator"></div>
    
    <div class="index-content">
        <div class="index-item level-1">
            <span class="index-number">1</span>
            <span class="index-title-pt">Identificação</span>
            <span class="index-dots"></span>
            <span class="index-page">3</span>
        </div>
        <div class="index-item-en">Identification</div>
        
        <div class="index-item level-1">
            <span class="index-number">2</span>
            <span class="index-title-pt">Materiais</span>
            <span class="index-dots"></span>
            <span class="index-page">5</span>
        </div>
        <div class="index-item-en">Materials</div>
        
        <div class="index-item level-2">
            <span class="index-number">2.1</span>
            <span class="index-title-pt">Certificados das matérias-primas</span>
            <span class="index-dots"></span>
            <span class="index-page">6</span>
        </div>
        <div class="index-item-en">Raw materials certificates</div>
        
        <div class="index-item level-2">
            <span class="index-number">2.2</span>
            <span class="index-title-pt">Consumíveis de soldagem</span>
            <span class="index-dots"></span>
            <span class="index-page">12</span>
        </div>
        <div class="index-item-en">Welding consumables</div>
    </div>
</div>

<style>
    .index-page {
        width: 210mm;
        min-height: 297mm;
        padding: 30mm 25mm;
        font-family: 'Open Sans', Arial, sans-serif;
    }
    
    .index-title {
        font-size: 36px;
        font-weight: bold;
        color: #1a365d;
        text-align: center;
        margin-bottom: 20px;
    }
    
    .index-separator {
        width: 100%;
        height: 2px;
        background: #2b6cb0;
        margin-bottom: 40px;
    }
    
    .index-item {
        display: flex;
        align-items: baseline;
        margin-bottom: 8px;
        font-size: 18px;
        color: #2d3748;
    }
    
    .index-item.level-1 {
        font-weight: bold;
        color: #1a365d;
        font-size: 20px;
        margin-top: 20px;
    }
    
    .index-item.level-2 {
        padding-left: 20px;
        font-size: 18px;
    }
    
    .index-item.level-3 {
        padding-left: 40px;
        font-size: 16px;
    }
    
    .index-number {
        min-width: 40px;
        font-weight: bold;
    }
    
    .index-title-pt {
        flex: 1;
    }
    
    .index-dots {
        flex: 1;
        border-bottom: 1px dotted #cbd5e0;
        margin: 0 10px;
    }
    
    .index-page {
        min-width: 40px;
        text-align: right;
        font-weight: bold;
    }
    
    .index-item-en {
        font-size: 16px;
        color: #718096;
        font-style: italic;
        margin-left: 40px;
        margin-bottom: 15px;
    }
</style>

3. Estrutura HTML - Divisora Estilo Minimalista

<div class="divider-minimal">
    <div class="divider-number-watermark">2</div>
    <div class="divider-content">
        <h1 class="divider-title">Materiais</h1>
        <h2 class="divider-subtitle">Materials</h2>
        <div class="divider-line"></div>
        <p class="divider-description">
            Certificados, especificações e documentação de matérias-primas
        </p>
    </div>
</div>

<style>
    .divider-minimal {
        width: 210mm;
        height: 297mm;
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        overflow: hidden;
        background: #ffffff;
    }
    
    .divider-number-watermark {
        position: absolute;
        font-size: 400px;
        font-weight: bold;
        color: #1a365d;
        opacity: 0.05;
        z-index: 1;
        line-height: 1;
    }
    
    .divider-content {
        position: relative;
        z-index: 2;
        text-align: center;
    }
    
    .divider-title {
        font-size: 72px;
        font-weight: bold;
        color: #1a365d;
        margin-bottom: 20px;
    }
    
    .divider-subtitle {
        font-size: 36px;
        color: #718096;
        font-style: italic;
        margin-bottom: 40px;
    }
    
    .divider-line {
        width: 200px;
        height: 4px;
        background: linear-gradient(90deg, transparent, #2b6cb0, transparent);
        margin: 0 auto 30px;
    }
    
    .divider-description {
        font-size: 20px;
        color: #4a5568;
    }
</style>

4. Estrutura HTML - Divisora Estilo Lateral

<div class="divider-lateral">
    <div class="divider-sidebar">
        <span class="divider-sidebar-number">3</span>
        <span class="divider-sidebar-icon"></span>
    </div>
    <div class="divider-main">
        <h1 class="divider-main-title">Procedimentos de Soldagem</h1>
        <h2 class="divider-main-subtitle">Welding Procedures</h2>
        <div class="divider-info-box">
            <p><strong>Projeto:</strong> BUZIOS 7</p>
            <p><strong>Cliente:</strong> SAIPEM</p>
            <p><strong>Contrato:</strong> OC 1472739</p>
        </div>
    </div>
</div>

<style>
    .divider-lateral {
        width: 210mm;
        height: 297mm;
        display: flex;
        background: #f7fafc;
    }
    
    .divider-sidebar {
        width: 80px;
        background: linear-gradient(180deg, #1a365d 0%, #2b6cb0 100%);
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        color: white;
    }
    
    .divider-sidebar-number {
        font-size: 96px;
        font-weight: bold;
        line-height: 1;
        margin-bottom: 30px;
    }
    
    .divider-sidebar-icon {
        font-size: 48px;
    }
    
    .divider-main {
        flex: 1;
        padding: 80px 60px;
        display: flex;
        flex-direction: column;
        justify-content: center;
    }
    
    .divider-main-title {
        font-size: 56px;
        font-weight: bold;
        color: #1a365d;
        margin-bottom: 15px;
        line-height: 1.2;
    }
    
    .divider-main-subtitle {
        font-size: 32px;
        color: #718096;
        font-style: italic;
        margin-bottom: 60px;
    }
    
    .divider-info-box {
        background: white;
        border: 2px solid #2b6cb0;
        border-radius: 8px;
        padding: 30px;
        box-shadow: 0 4px 6px rgba(0,0,0,0.1);
    }
    
    .divider-info-box p {
        font-size: 18px;
        color: #2d3748;
        margin: 10px 0;
    }
    
    .divider-info-box strong {
        color: #1a365d;
    }
</style>

5. Estrutura HTML - Cabeçalho e Rodapé

<!-- CABEÇALHO -->
<div class="page-header">
    <div class="header-left">
        <img src="{{logo_url}}" alt="Logo" class="header-logo">
    </div>
    <div class="header-center">
        <span class="header-project">{{project_name}}</span>
    </div>
    <div class="header-right">
        <span class="header-doc">{{document_number}}</span>
    </div>
</div>

<!-- RODAPÉ -->
<div class="page-footer">
    <div class="footer-left">
        <span>Rev. {{revision}}</span>
    </div>
    <div class="footer-center">
        <span class="page-number">{{page_number}}</span>
    </div>
    <div class="footer-right">
        <span>{{date}}</span>
    </div>
</div>

<style>
    .page-header {
        width: 100%;
        height: 60px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 30px;
        border-bottom: 2px solid #2b6cb0;
        background: white;
        font-family: 'Roboto', Arial, sans-serif;
    }
    
    .header-logo {
        height: 40px;
        object-fit: contain;
    }
    
    .header-center {
        flex: 1;
        text-align: center;
        font-size: 14px;
        font-weight: 500;
        color: #1a365d;
    }
    
    .header-right {
        font-size: 12px;
        color: #718096;
    }
    
    .page-footer {
        width: 100%;
        height: 40px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0 30px;
        border-top: 1px solid #cbd5e0;
        background: white;
        font-size: 12px;
        color: #4a5568;
    }
    
    .footer-center .page-number {
        font-size: 18px;
        font-weight: bold;
        color: #1a365d;
    }
</style>

6. JavaScript - Sistema de Variáveis Dinâmicas

// Classe para gerenciar templates
class DatabookTemplate {
    constructor(config) {
        this.config = config;
        this.variables = {};
    }
    
    // Define variáveis do projeto
    setVariables(vars) {
        this.variables = { ...this.variables, ...vars };
    }
    
    // Renderiza template substituindo variáveis
    render(templateHtml) {
        let rendered = templateHtml;
        
        // Substitui variáveis no formato {{variable_name}}
        for (const [key, value] of Object.entries(this.variables)) {
            const regex = new RegExp(`{{${key}}}`, 'g');
            rendered = rendered.replace(regex, value);
        }
        
        return rendered;
    }
    
    // Gera capa frontal
    generateCover() {
        const coverTemplate = `
            <div class="cover-page">
                <img src="{{client_logo}}" class="client-logo">
                <h1>{{project_title}}</h1>
                <h2>{{project_subtitle}}</h2>
                <div class="cover-info">
                    <p>Documento: {{document_number}}</p>
                    <p>Contrato: {{contract_number}}</p>
                    <p>Data: {{issue_date}}</p>
                </div>
                <img src="{{supplier_logo}}" class="supplier-logo">
            </div>
        `;
        
        return this.render(coverTemplate);
    }
    
    // Gera índice
    generateIndex(sections) {
        let indexHtml = '<div class="index-page"><h1>ÍNDICE / TABLE OF CONTENTS</h1>';
        
        sections.forEach(section => {
            const indent = section.level > 1 ? `level-${section.level}` : '';
            indexHtml += `
                <div class="index-item ${indent}">
                    <span class="index-number">${section.number}</span>
                    <span class="index-title">${section.title_pt}</span>
                    <span class="index-dots"></span>
                    <span class="index-page">${section.page}</span>
                </div>
                <div class="index-item-en">${section.title_en}</div>
            `;
        });
        
        indexHtml += '</div>';
        return indexHtml;
    }
    
    // Gera divisora de seção
    generateDivider(sectionNumber, titlePt, titleEn, style = 'minimal') {
        const templates = {
            minimal: `
                <div class="divider-minimal">
                    <div class="divider-number-watermark">${sectionNumber}</div>
                    <div class="divider-content">
                        <h1>${titlePt}</h1>
                        <h2>${titleEn}</h2>
                    </div>
                </div>
            `,
            lateral: `
                <div class="divider-lateral">
                    <div class="divider-sidebar">
                        <span>${sectionNumber}</span>
                    </div>
                    <div class="divider-main">
                        <h1>${titlePt}</h1>
                        <h2>${titleEn}</h2>
                    </div>
                </div>
            `,
            corporate: `
                <div class="divider-corporate">
                    <div class="divider-header">
                        <img src="{{client_logo}}">
                    </div>
                    <div class="divider-body">
                        <span class="section-number">${sectionNumber}</span>
                        <h1>${titlePt}</h1>
                        <h2>${titleEn}</h2>
                    </div>
                </div>
            `
        };
        
        return this.render(templates[style] || templates.minimal);
    }
}

// Exemplo de uso
const template = new DatabookTemplate({
    name: 'SAIPEM Vendor Databook',
    version: '1.0'
});

template.setVariables({
    project_title: 'BUZIOS 7 PRODUCTION SYSTEM DEVELOPMENT',
    project_subtitle: 'AR HEAD FABRICATION LONG',
    client_logo: '/logos/saipem.png',
    supplier_logo: '/logos/engemetal.png',
    document_number: 'DB-B97-01_S1_VENDOR_DATABOOK',
    contract_number: 'OC 1472739',
    issue_date: '2024-11-17'
});

// Gerar componentes
const cover = template.generateCover();
const index = template.generateIndex([
    { number: '1', title_pt: 'Identificação', title_en: 'Identification', level: 1, page: 3 },
    { number: '2', title_pt: 'Materiais', title_en: 'Materials', level: 1, page: 5 }
]);
const divider = template.generateDivider('2', 'Materiais', 'Materials', 'minimal');

7. CSS - Variáveis Customizáveis

:root {
    /* Cores Primárias */
    --color-primary: #1a365d;
    --color-secondary: #2b6cb0;
    --color-accent: #4299e1;
    
    /* Cores Neutras */
    --color-gray-dark: #2d3748;
    --color-gray-medium: #718096;
    --color-gray-light: #e2e8f0;
    
    /* Tipografia */
    --font-heading: 'Roboto', Arial, sans-serif;
    --font-body: 'Open Sans', Arial, sans-serif;
    --font-mono: 'Roboto Mono', monospace;
    
    /* Tamanhos de Fonte */
    --font-size-h1: 60px;
    --font-size-h2: 48px;
    --font-size-h3: 36px;
    --font-size-h4: 24px;
    --font-size-body: 16px;
    --font-size-small: 12px;
    
    /* Espaçamentos */
    --spacing-xs: 8px;
    --spacing-sm: 16px;
    --spacing-md: 24px;
    --spacing-lg: 40px;
    --spacing-xl: 60px;
    
    /* Bordas */
    --border-radius: 8px;
    --border-width: 2px;
}

/* Aplicação das variáveis */
.cover-title {
    color: var(--color-primary);
    font-family: var(--font-heading);
    font-size: var(--font-size-h1);
}

.index-item {
    color: var(--color-gray-dark);
    font-family: var(--font-body);
    padding: var(--spacing-sm) 0;
}

.divider-content {
    padding: var(--spacing-xl);
}

/* Tema alternativo - Azul Claro */
.theme-light {
    --color-primary: #2563eb;
    --color-secondary: #60a5fa;
    --color-accent: #93c5fd;
}

/* Tema alternativo - Cinza Profissional */
.theme-professional {
    --color-primary: #334155;
    --color-secondary: #64748b;
    --color-accent: #94a3b8;
}

8. Integração com Banco de Dados (Supabase)

-- Tabela de Templates
CREATE TABLE templates (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    nome VARCHAR(255) NOT NULL,
    descricao TEXT,
    versao VARCHAR(20) DEFAULT '1.0',
    config JSONB NOT NULL,
    criado_por UUID REFERENCES auth.users(id),
    criado_em TIMESTAMP DEFAULT NOW(),
    atualizado_em TIMESTAMP DEFAULT NOW(),
    ativo BOOLEAN DEFAULT true,
    publico BOOLEAN DEFAULT false,
    organizacao_id UUID REFERENCES organizacoes(id)
);

-- Exemplo de config JSONB
{
    "capa": {
        "titulo": "{{project_title}}",
        "subtitulo": "{{project_subtitle}}",
        "cores": {
            "primaria": "#1a365d",
            "secundaria": "#2b6cb0"
        }
    },
    "indice": {
        "bilingue": true,
        "estrutura": [
            {
                "numero": "1",
                "titulo_pt": "Identificação",
                "titulo_en": "Identification",
                "nivel": 1
            }
        ]
    },
    "divisoras": {
        "estilo": "minimal"
    }
}

-- Tabela de Databooks usando Templates
CREATE TABLE databooks (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    nome VARCHAR(255) NOT NULL,
    template_id UUID REFERENCES templates(id),
    dados JSONB NOT NULL,
    criado_em TIMESTAMP DEFAULT NOW()
);

-- Query para buscar templates
SELECT t.*, u.nome as criador
FROM templates t
LEFT JOIN auth.users u ON t.criado_por = u.id
WHERE t.ativo = true
  AND (t.publico = true OR t.organizacao_id = $1)
ORDER BY t.criado_em DESC;

-- Query para aplicar template a databook
UPDATE databooks
SET template_id = $1,
    dados = jsonb_set(dados, '{template_aplicado}', 'true'::jsonb)
WHERE id = $2;

9. API Endpoints (Node.js/Express)

const express = require('express');
const router = express.Router();

// GET /api/templates - Lista templates
router.get('/templates', async (req, res) => {
    try {
        const { data, error } = await supabase
            .from('templates')
            .select('*')
            .eq('ativo', true)
            .order('criado_em', { ascending: false });
        
        if (error) throw error;
        res.json({ success: true, data });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

// POST /api/templates - Cria novo template
router.post('/templates', async (req, res) => {
    try {
        const { nome, descricao, config } = req.body;
        
        const { data, error } = await supabase
            .from('templates')
            .insert([{
                nome,
                descricao,
                config,
                criado_por: req.user.id
            }])
            .select()
            .single();
        
        if (error) throw error;
        res.json({ success: true, data });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

// PUT /api/templates/:id - Atualiza template
router.put('/templates/:id', async (req, res) => {
    try {
        const { id } = req.params;
        const { nome, descricao, config } = req.body;
        
        const { data, error } = await supabase
            .from('templates')
            .update({
                nome,
                descricao,
                config,
                atualizado_em: new Date().toISOString()
            })
            .eq('id', id)
            .select()
            .single();
        
        if (error) throw error;
        res.json({ success: true, data });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

// POST /api/databooks/:id/apply-template - Aplica template
router.post('/databooks/:id/apply-template', async (req, res) => {
    try {
        const { id } = req.params;
        const { template_id } = req.body;
        
        // Buscar template
        const { data: template } = await supabase
            .from('templates')
            .select('*')
            .eq('id', template_id)
            .single();
        
        // Buscar databook
        const { data: databook } = await supabase
            .from('databooks')
            .select('*')
            .eq('id', id)
            .single();
        
        // Aplicar configurações do template
        const dadosAtualizados = {
            ...databook.dados,
            template_config: template.config
        };
        
        // Atualizar databook
        const { data, error } = await supabase
            .from('databooks')
            .update({
                template_id,
                dados: dadosAtualizados
            })
            .eq('id', id)
            .select()
            .single();
        
        if (error) throw error;
        res.json({ success: true, data });
    } catch (error) {
        res.status(500).json({ success: false, error: error.message });
    }
});

module.exports = router;

10. Geração de PDF com Puppeteer

const puppeteer = require('puppeteer');
const fs = require('fs');

class DatabookPDFGenerator {
    constructor(template, databook) {
        this.template = template;
        this.databook = databook;
    }
    
    async generatePDF(outputPath) {
        const browser = await puppeteer.launch({
            headless: true,
            args: ['--no-sandbox']
        });
        
        const page = await browser.newPage();
        
        // Configurar página
        await page.setViewport({
            width: 794,  // A4 width in pixels at 96 DPI
            height: 1123 // A4 height in pixels at 96 DPI
        });
        
        // Gerar HTML completo
        const htmlContent = this.generateFullHTML();
        
        // Carregar conteúdo
        await page.setContent(htmlContent, {
            waitUntil: 'networkidle0'
        });
        
        // Gerar PDF
        await page.pdf({
            path: outputPath,
            format: 'A4',
            printBackground: true,
            margin: {
                top: '20mm',
                right: '15mm',
                bottom: '20mm',
                left: '15mm'
            },
            displayHeaderFooter: true,
            headerTemplate: this.generateHeader(),
            footerTemplate: this.generateFooter()
        });
        
        await browser.close();
        
        return outputPath;
    }
    
    generateFullHTML() {
        const sections = [];
        
        // Capa
        sections.push(this.generateCover());
        
        // Índice
        sections.push(this.generateIndex());
        
        // Seções com divisoras
        this.databook.sections.forEach(section => {
            sections.push(this.generateDivider(section));
            sections.push(this.generateSectionContent(section));
        });
        
        return `
            <!DOCTYPE html>
            <html>
            <head>
                <meta charset="UTF-8">
                <style>${this.getStyles()}</style>
            </head>
            <body>
                ${sections.join('\n<div class="page-break"></div>\n')}
            </body>
            </html>
        `;
    }
    
    generateHeader() {
        return `
            <div style="font-size: 10px; padding: 0 20px; width: 100%;">
                <span>${this.databook.project_name}</span>
            </div>
        `;
    }
    
    generateFooter() {
        return `
            <div style="font-size: 10px; padding: 0 20px; width: 100%; text-align: center;">
                <span class="pageNumber"></span> / <span class="totalPages"></span>
            </div>
        `;
    }
    
    getStyles() {
        return fs.readFileSync('./styles/databook.css', 'utf8');
    }
}

// Uso
const generator = new DatabookPDFGenerator(template, databook);
await generator.generatePDF('./output/databook.pdf');

Conclusão

Estes exemplos fornecem uma base sólida para implementar o sistema de templates no SteelBook. Adapte conforme necessário para sua arquitetura específica.