major restructure

This commit is contained in:
buenosairesam
2026-01-20 05:31:26 -03:00
parent 27b32deba4
commit e4052374db
328 changed files with 1018 additions and 10018 deletions

View File

@@ -0,0 +1,335 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ filename }} - Ops Template</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, -apple-system, sans-serif;
background: #f8fafc;
color: #1e293b;
line-height: 1.6;
}
.container { max-width: 800px; margin: 0 auto; padding: 2rem 1rem; }
header { margin-bottom: 1.5rem; }
.breadcrumb { font-size: 0.9rem; color: #64748b; margin-bottom: 0.5rem; }
.breadcrumb a { color: #15803d; text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
h1 { font-size: 1.5rem; color: #15803d; }
.meta {
display: flex;
gap: 0.5rem;
margin-top: 0.5rem;
font-size: 0.8rem;
}
.meta span {
background: #f1f5f9;
padding: 0.2rem 0.5rem;
border-radius: 4px;
color: #64748b;
}
.meta .sample { background: #fef3c7; color: #92400e; }
/* Form-like styling */
.form-card {
background: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
overflow: hidden;
}
.form-header {
background: linear-gradient(135deg, #15803d, #22c55e);
color: white;
padding: 1rem 1.5rem;
}
.form-header h2 { font-size: 1.1rem; font-weight: 600; }
.form-body { padding: 1.5rem; }
.field {
margin-bottom: 1.25rem;
}
.field:last-child { margin-bottom: 0; }
.field-label {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #64748b;
margin-bottom: 0.35rem;
}
.field-label .edit-icon {
cursor: pointer;
opacity: 0.5;
font-size: 0.85rem;
}
.field-label .edit-icon:hover {
opacity: 1;
}
.field-value {
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 6px;
padding: 0.75rem;
font-size: 0.95rem;
color: #1e293b;
min-height: 2.5rem;
}
.field-value:focus-within {
border-color: #15803d;
outline: none;
box-shadow: 0 0 0 3px rgba(21, 128, 61, 0.1);
}
.field-value.multiline {
min-height: 4rem;
}
.field-value ul, .field-value ol {
margin: 0;
padding-left: 1.25rem;
}
.field-value li {
margin-bottom: 0.25rem;
}
.field-value p {
margin: 0 0 0.5rem 0;
}
.field-value p:last-child { margin-bottom: 0; }
.field-textarea {
display: none;
width: 100%;
min-height: 100px;
padding: 0.75rem;
font-size: 0.95rem;
font-family: inherit;
border: 1px solid #15803d;
border-radius: 6px;
resize: vertical;
box-shadow: 0 0 0 3px rgba(21, 128, 61, 0.1);
}
.field.editing .field-value { display: none; }
.field.editing .field-textarea { display: block; }
/* Special field styles */
.field-steps .field-value {
counter-reset: step;
padding-left: 0.5rem;
}
.field-steps ol {
list-style: none;
padding-left: 0;
}
.field-steps li {
position: relative;
padding-left: 2rem;
margin-bottom: 0.5rem;
}
.field-steps li::before {
counter-increment: step;
content: counter(step);
position: absolute;
left: 0;
width: 1.5rem;
height: 1.5rem;
background: #15803d;
color: white;
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
}
.field-problems .field-value {
background: #fef2f2;
border-color: #fecaca;
}
.field-problems li::before {
content: '!';
color: #dc2626;
font-weight: bold;
margin-right: 0.5rem;
}
.field-special .field-value {
background: #fffbeb;
border-color: #fde68a;
}
.field-technical .field-value {
background: #f0fdf4;
border-color: #bbf7d0;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
}
.field-technical code {
background: #dcfce7;
padding: 0.1rem 0.35rem;
border-radius: 3px;
font-size: 0.85em;
}
.sidebar {
margin-top: 1.5rem;
padding: 1rem;
background: #f0fdf4;
border: 1px solid #bbf7d0;
border-radius: 8px;
}
.sidebar h3 { font-size: 0.8rem; color: #15803d; margin-bottom: 0.75rem; text-transform: uppercase; }
.sidebar a {
display: block;
color: #15803d;
text-decoration: none;
padding: 0.35rem 0;
font-size: 0.9rem;
}
.sidebar a:hover { text-decoration: underline; }
footer {
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid #e2e8f0;
font-size: 0.85rem;
}
footer a { color: #15803d; text-decoration: none; }
footer a:hover { text-decoration: underline; }
</style>
</head>
<body>
<div class="container">
<header>
<div class="breadcrumb">
<a href="/">Album</a> / <a href="/book/ops-templates/">Ops Templates</a> / {{ user_type }}
</div>
<h1>{{ filename.replace('.md', '').replace('-', ' ').title() }}</h1>
<div class="meta">
<span>{{ user_type }}</span>
<span class="sample">Sample</span>
</div>
</header>
<div class="form-card">
<div class="form-header">
<h2>User Flow Template</h2>
</div>
<div class="form-body" id="form-content">
<!-- Content will be parsed and inserted here -->
</div>
</div>
<div class="sidebar">
<h3>Related</h3>
<a href="/book/gherkin/es/{{ user_type }}/{{ filename.replace('.md', '.feature') }}">Gherkin (Spanish)</a>
<a href="/book/gherkin/en/{{ user_type }}/{{ filename.replace('.md', '.feature') }}">Gherkin (English)</a>
<a href="/book/feature-flow/">Feature Flow Pipeline</a>
</div>
<footer>
<a href="/book/ops-templates/">&larr; All Templates</a>
</footer>
</div>
<script>
const rawContent = {{ content | tojson }};
function parseMarkdown(md) {
const sections = {};
let currentSection = null;
let currentContent = [];
const lines = md.split('\n');
for (const line of lines) {
if (line.startsWith('## ')) {
if (currentSection) {
sections[currentSection] = currentContent.join('\n').trim();
}
currentSection = line.replace('## ', '').trim();
currentContent = [];
} else if (line.startsWith('# ')) {
sections['_title'] = line.replace('# ', '').trim();
} else if (currentSection) {
currentContent.push(line);
}
}
if (currentSection) {
sections[currentSection] = currentContent.join('\n').trim();
}
return sections;
}
function formatContent(content) {
if (!content) return '';
// Convert markdown lists to HTML
let html = content
.replace(/^(\d+)\.\s+(.*)$/gm, '<li>$2</li>')
.replace(/^-\s+(.*)$/gm, '<li>$1</li>')
.replace(/`([^`]+)`/g, '<code>$1</code>');
// Wrap consecutive li elements in ul/ol
if (html.includes('<li>')) {
if (content.match(/^\d+\./m)) {
html = '<ol>' + html + '</ol>';
} else {
html = '<ul>' + html + '</ul>';
}
}
// Convert line breaks to paragraphs for non-list content
if (!html.includes('<li>')) {
html = html.split('\n').filter(l => l.trim()).map(l => '<p>' + l + '</p>').join('');
}
return html;
}
function createField(label, content, className = '') {
if (!content) return '';
return `
<div class="field ${className}">
<label class="field-label">${label} <span class="edit-icon" onclick="toggleEdit(this)" title="Edit field">&#9998;</span></label>
<div class="field-value ${content.includes('\n') ? 'multiline' : ''}">${formatContent(content)}</div>
<textarea class="field-textarea">${content}</textarea>
</div>
`;
}
function toggleEdit(icon) {
const field = icon.closest('.field');
field.classList.toggle('editing');
if (field.classList.contains('editing')) {
field.querySelector('.field-textarea').focus();
}
}
const sections = parseMarkdown(rawContent);
const container = document.getElementById('form-content');
const fieldMap = [
{ key: 'Tipo de usuario', label: 'Tipo de Usuario', class: '' },
{ key: 'Donde empieza', label: 'Punto de Entrada', class: '' },
{ key: 'Que quiere hacer el usuario', label: 'Objetivo del Usuario', class: '' },
{ key: 'Pasos', label: 'Pasos', class: 'field-steps' },
{ key: 'Que deberia pasar', label: 'Resultado Esperado', class: '' },
{ key: 'Problemas comunes', label: 'Problemas Comunes', class: 'field-problems' },
{ key: 'Casos especiales', label: 'Casos Especiales', class: 'field-special' },
{ key: 'Flujos relacionados', label: 'Flujos Relacionados', class: '' },
{ key: 'Notas tecnicas', label: 'Notas Tecnicas', class: 'field-technical' },
];
let html = '';
for (const field of fieldMap) {
if (sections[field.key]) {
html += createField(field.label, sections[field.key], field.class);
}
}
container.innerHTML = html;
</script>
</body>
</html>