chore: add template folder
This commit is contained in:
parent
4d6fe85f53
commit
d33aeef1af
163
templates/blog-post.html
Normal file
163
templates/blog-post.html
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{title}} - {{site_name | default(value="My Blog")}}</title>
|
||||||
|
<meta name="description" content="{{description | default(value=content | excerpt(length=160))}}">
|
||||||
|
{% if author %}
|
||||||
|
<meta name="author" content="{{author}}">
|
||||||
|
{% endif %}
|
||||||
|
{% if tags %}
|
||||||
|
<meta name="keywords" content="{{tags | join(sep=', ')}}">
|
||||||
|
{% endif %}
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background: white;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 2.5em;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
.meta {
|
||||||
|
color: #7f8c8d;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.meta span {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
font-size: 1.1em;
|
||||||
|
line-height: 1.8;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.tags {
|
||||||
|
margin-top: 40px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.tag {
|
||||||
|
display: inline-block;
|
||||||
|
background: #3498db;
|
||||||
|
color: white;
|
||||||
|
padding: 5px 12px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 0.85em;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.tag:hover {
|
||||||
|
background: #2980b9;
|
||||||
|
}
|
||||||
|
.reading-time {
|
||||||
|
color: #95a5a6;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.share-buttons {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.share-button {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background: #34495e;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.share-button:hover {
|
||||||
|
background: #2c3e50;
|
||||||
|
}
|
||||||
|
.back-link {
|
||||||
|
margin-top: 40px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.back-link a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.back-link a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
<div class="meta">
|
||||||
|
{% if author %}
|
||||||
|
<span>By {{author}}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if published_date %}
|
||||||
|
<span>Published on {{published_date | date_format(format="%B %d, %Y")}}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if reading_time %}
|
||||||
|
<span class="reading-time">{{reading_time}} min read</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{% if featured_image %}
|
||||||
|
<img src="{{featured_image}}" alt="{{title}}" style="width: 100%; height: auto; margin-bottom: 20px; border-radius: 5px;">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{content | markdown | safe}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if tags %}
|
||||||
|
<div class="tags">
|
||||||
|
<strong>Tags:</strong>
|
||||||
|
{% for tag in tags %}
|
||||||
|
<a href="/tag/{{tag | slug}}" class="tag">{{tag}}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if enable_sharing %}
|
||||||
|
<div class="share-buttons">
|
||||||
|
<strong>Share this post:</strong><br>
|
||||||
|
<a href="https://twitter.com/intent/tweet?text={{title | urlencode}}&url={{page_url | urlencode}}" class="share-button" target="_blank">Twitter</a>
|
||||||
|
<a href="https://www.facebook.com/sharer/sharer.php?u={{page_url | urlencode}}" class="share-button" target="_blank">Facebook</a>
|
||||||
|
<a href="https://www.linkedin.com/sharing/share-offsite/?url={{page_url | urlencode}}" class="share-button" target="_blank">LinkedIn</a>
|
||||||
|
<a href="mailto:?subject={{title | urlencode}}&body={{page_url | urlencode}}" class="share-button">Email</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<div class="back-link">
|
||||||
|
<a href="{{back_url | default(value='/')}}">← Back to {{back_text | default(value='Home')}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if analytics_id %}
|
||||||
|
<script>
|
||||||
|
// Add analytics tracking here if needed
|
||||||
|
console.log('Analytics ID: {{analytics_id}}');
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
</body>
|
||||||
|
</html>
|
296
templates/email/README.md
Normal file
296
templates/email/README.md
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
# Email Templates Structure
|
||||||
|
|
||||||
|
This directory contains internationalized email templates for the Rustelo framework. Templates are organized by language and support both HTML and text formats.
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
templates/email/
|
||||||
|
├── en_/ # English templates (default language)
|
||||||
|
│ ├── html/ # HTML email templates
|
||||||
|
│ │ ├── contact.hbs # Contact form submission
|
||||||
|
│ │ ├── notification.hbs # General notifications
|
||||||
|
│ │ └── welcome.hbs # Welcome email (example)
|
||||||
|
│ └── text/ # Plain text email templates
|
||||||
|
│ ├── contact.hbs # Contact form submission
|
||||||
|
│ ├── notification.hbs # General notifications
|
||||||
|
│ └── welcome.hbs # Welcome email (example)
|
||||||
|
├── es_/ # Spanish templates
|
||||||
|
│ ├── html/
|
||||||
|
│ └── text/
|
||||||
|
├── fr_/ # French templates (example)
|
||||||
|
│ ├── html/
|
||||||
|
│ └── text/
|
||||||
|
└── README.md # This file
|
||||||
|
```
|
||||||
|
|
||||||
|
## Language Naming Convention
|
||||||
|
|
||||||
|
- Language directories must end with an underscore (`_`)
|
||||||
|
- Use ISO 639-1 language codes (e.g., `en`, `es`, `fr`, `de`)
|
||||||
|
- Examples: `en_`, `es_`, `fr_`, `de_`, `it_`, `pt_`, `ru_`, `ja_`, `ko_`, `zh_`
|
||||||
|
|
||||||
|
## Template Naming Convention
|
||||||
|
|
||||||
|
Templates are automatically registered with the naming pattern: `{language}_{template_name}_{format}`
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- `en_contact_html` - English contact form HTML template
|
||||||
|
- `es_contact_text` - Spanish contact form text template
|
||||||
|
- `fr_notification_html` - French notification HTML template
|
||||||
|
|
||||||
|
## Language Fallback
|
||||||
|
|
||||||
|
The email system provides automatic language fallback:
|
||||||
|
|
||||||
|
1. **Requested Language**: First tries the specific language (e.g., `es_contact_html`)
|
||||||
|
2. **Default Language**: Falls back to English (`en_contact_html`)
|
||||||
|
3. **Legacy Support**: Falls back to templates without language prefix (`contact_html`)
|
||||||
|
|
||||||
|
## Creating New Templates
|
||||||
|
|
||||||
|
### 1. Create Language Directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p templates/email/fr_/html
|
||||||
|
mkdir -p templates/email/fr_/text
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create Template Files
|
||||||
|
|
||||||
|
Create both HTML and text versions for each template:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# HTML version
|
||||||
|
touch templates/email/fr_/html/contact.hbs
|
||||||
|
touch templates/email/fr_/html/notification.hbs
|
||||||
|
|
||||||
|
# Text version
|
||||||
|
touch templates/email/fr_/text/contact.hbs
|
||||||
|
touch templates/email/fr_/text/notification.hbs
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Template Content Structure
|
||||||
|
|
||||||
|
Each template should use Handlebars syntax and include appropriate variables:
|
||||||
|
|
||||||
|
**Contact Form Variables:**
|
||||||
|
- `{{name}}` - Sender's name
|
||||||
|
- `{{email}}` - Sender's email
|
||||||
|
- `{{subject}}` - Message subject
|
||||||
|
- `{{message}}` - Message content
|
||||||
|
- `{{form_type}}` - Type of form (contact, support, etc.)
|
||||||
|
- `{{submitted_at}}` - Submission timestamp
|
||||||
|
- `{{ip_address}}` - Sender's IP address (optional)
|
||||||
|
- `{{user_agent}}` - Sender's browser info (optional)
|
||||||
|
- `{{fields}}` - Additional form fields (optional)
|
||||||
|
|
||||||
|
**Notification Variables:**
|
||||||
|
- `{{title}}` - Notification title
|
||||||
|
- `{{message}}` - Notification message
|
||||||
|
- `{{content}}` - Additional content (optional)
|
||||||
|
- `{{type}}` - Notification type (info, warning, success, danger)
|
||||||
|
- `{{action_url}}` - Call-to-action URL (optional)
|
||||||
|
- `{{action_text}}` - Call-to-action text (optional)
|
||||||
|
- `{{timestamp}}` - Notification timestamp
|
||||||
|
|
||||||
|
## Available Handlebars Helpers
|
||||||
|
|
||||||
|
The email system provides several custom helpers:
|
||||||
|
|
||||||
|
### Date Formatting
|
||||||
|
```handlebars
|
||||||
|
{{date_format submitted_at "%B %d, %Y at %I:%M %p UTC"}}
|
||||||
|
{{date_format submitted_at "%d de %B de %Y a las %H:%M UTC"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Text Manipulation
|
||||||
|
```handlebars
|
||||||
|
{{capitalize form_type}} <!-- "contact" → "Contact" -->
|
||||||
|
{{truncate user_agent 100}} <!-- Limit text to 100 characters -->
|
||||||
|
{{default action_text "Click Here"}} <!-- Use default if empty -->
|
||||||
|
{{url_encode email}} <!-- URL encode text -->
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conditional Content
|
||||||
|
```handlebars
|
||||||
|
{{#if fields}}
|
||||||
|
Additional fields are present
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#each fields}}
|
||||||
|
{{@key}}: {{this}}
|
||||||
|
{{/each}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Language Detection
|
||||||
|
|
||||||
|
The email system automatically detects the preferred language from:
|
||||||
|
|
||||||
|
1. **User Profile**: User's saved language preference (if authenticated)
|
||||||
|
2. **Request Headers**: `Accept-Language` HTTP header
|
||||||
|
3. **Default Fallback**: English (`en`)
|
||||||
|
|
||||||
|
### Supported Languages
|
||||||
|
|
||||||
|
The system currently supports these language codes:
|
||||||
|
- `en` - English
|
||||||
|
- `es` - Spanish
|
||||||
|
- `fr` - French
|
||||||
|
- `de` - German
|
||||||
|
- `it` - Italian
|
||||||
|
- `pt` - Portuguese
|
||||||
|
- `ru` - Russian
|
||||||
|
- `ja` - Japanese
|
||||||
|
- `ko` - Korean
|
||||||
|
- `zh` - Chinese
|
||||||
|
|
||||||
|
## Using Templates in Code
|
||||||
|
|
||||||
|
### Server-side Usage
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Send with automatic language detection
|
||||||
|
email_service.send_contact_form(
|
||||||
|
"John Doe",
|
||||||
|
"john@example.com",
|
||||||
|
"Question",
|
||||||
|
"Message content",
|
||||||
|
"admin@app.com"
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
// Send with specific language
|
||||||
|
email_service.send_contact_form_with_language(
|
||||||
|
"Juan Pérez",
|
||||||
|
"juan@example.com",
|
||||||
|
"Pregunta",
|
||||||
|
"Contenido del mensaje",
|
||||||
|
"admin@app.com",
|
||||||
|
"es" // Spanish
|
||||||
|
).await?;
|
||||||
|
|
||||||
|
// Send templated email
|
||||||
|
email_service.send_templated_email_with_language(
|
||||||
|
"user@example.com",
|
||||||
|
"Welcome!",
|
||||||
|
"welcome",
|
||||||
|
template_data,
|
||||||
|
"fr" // French
|
||||||
|
).await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Client-side Language
|
||||||
|
|
||||||
|
The contact and support form components automatically detect language from browser headers:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Language is automatically detected from Accept-Language header
|
||||||
|
<ContactForm
|
||||||
|
recipient="contact@yourapp.com"
|
||||||
|
title="Contact Us"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Template Best Practices
|
||||||
|
|
||||||
|
### 1. Consistency
|
||||||
|
- Use consistent styling across all language versions
|
||||||
|
- Maintain the same structure and layout
|
||||||
|
- Keep variable names identical across languages
|
||||||
|
|
||||||
|
### 2. Cultural Considerations
|
||||||
|
- Adapt date formats for different regions
|
||||||
|
- Consider right-to-left languages if needed
|
||||||
|
- Use appropriate salutations and closings
|
||||||
|
- Respect cultural communication norms
|
||||||
|
|
||||||
|
### 3. Content Guidelines
|
||||||
|
- Keep translations accurate and natural
|
||||||
|
- Use professional tone appropriate for business communication
|
||||||
|
- Include all necessary legal disclaimers
|
||||||
|
- Test with native speakers when possible
|
||||||
|
|
||||||
|
### 4. HTML Best Practices
|
||||||
|
- Use semantic HTML structure
|
||||||
|
- Include proper `lang` attribute in HTML templates
|
||||||
|
- Ensure responsive design for mobile devices
|
||||||
|
- Use accessible color contrasts
|
||||||
|
- Include fallback fonts for different character sets
|
||||||
|
|
||||||
|
### 5. Text Templates
|
||||||
|
- Keep plain text versions readable and well-formatted
|
||||||
|
- Use appropriate line breaks and spacing
|
||||||
|
- Include all important information from HTML version
|
||||||
|
- Test rendering in various email clients
|
||||||
|
|
||||||
|
## Testing Templates
|
||||||
|
|
||||||
|
### 1. Development Testing
|
||||||
|
Use the console provider to see rendered templates:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
provider = "console"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Language Testing
|
||||||
|
Test specific languages by setting Accept-Language header:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "Accept-Language: es-ES,es;q=0.9" \
|
||||||
|
-X POST /api/email/contact \
|
||||||
|
-d '{"name":"Test","email":"test@example.com","subject":"Test","message":"Test"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Template Validation
|
||||||
|
- Verify all variables are properly escaped
|
||||||
|
- Check for proper fallback behavior
|
||||||
|
- Test with various data inputs
|
||||||
|
- Validate HTML structure and accessibility
|
||||||
|
|
||||||
|
## Migration from Legacy Templates
|
||||||
|
|
||||||
|
If you have existing templates without language prefixes:
|
||||||
|
|
||||||
|
1. **Backup existing templates**
|
||||||
|
2. **Create language directories** (`en_/html/`, `en_/text/`)
|
||||||
|
3. **Move templates** to appropriate language directories
|
||||||
|
4. **Update template names** to remove language prefixes
|
||||||
|
5. **Test thoroughly** to ensure proper fallback behavior
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Email template directory is configured in your application config:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[email]
|
||||||
|
# Template directory (relative to root_path)
|
||||||
|
template_dir = "templates/email"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or via environment variable:
|
||||||
|
```bash
|
||||||
|
EMAIL_TEMPLATE_DIR=/path/to/templates/email
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Template Not Found Errors
|
||||||
|
1. Check directory structure and naming convention
|
||||||
|
2. Verify template files exist and are readable
|
||||||
|
3. Check log output for specific template name being requested
|
||||||
|
4. Ensure language fallback is working properly
|
||||||
|
|
||||||
|
### Language Detection Issues
|
||||||
|
1. Verify Accept-Language header format
|
||||||
|
2. Check supported language list
|
||||||
|
3. Test with explicit language parameter
|
||||||
|
4. Review language detection logs
|
||||||
|
|
||||||
|
### Rendering Issues
|
||||||
|
1. Validate Handlebars syntax
|
||||||
|
2. Check for missing variables
|
||||||
|
3. Test with sample data
|
||||||
|
4. Verify helper function usage
|
||||||
|
|
||||||
|
For more detailed troubleshooting, see the main email system documentation.
|
217
templates/email/en_/html/contact.hbs
Normal file
217
templates/email/en_/html/contact.hbs
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Contact Form Submission</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.header p {
|
||||||
|
margin: 10px 0 0 0;
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.field {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-left: 4px solid #667eea;
|
||||||
|
}
|
||||||
|
.field-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 14px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.field-value {
|
||||||
|
color: #212529;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.message-field {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.message-field .field-value {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.metadata {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.metadata h3 {
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.metadata-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.metadata-label {
|
||||||
|
color: #6c757d;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.metadata-value {
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
}
|
||||||
|
.footer p {
|
||||||
|
margin: 0;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.highlight {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
border: 1px solid #ffeaa7;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.highlight strong {
|
||||||
|
color: #856404;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.header, .content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.metadata-item {
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.metadata-label {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>📧 New Contact Form Submission</h1>
|
||||||
|
<p>You have received a new message from your website</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div class="highlight">
|
||||||
|
<strong>Reply directly to this email</strong> to respond to the sender, or use the contact information below.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Name</div>
|
||||||
|
<div class="field-value">{{name}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Email Address</div>
|
||||||
|
<div class="field-value">
|
||||||
|
<a href="mailto:{{email}}" style="color: #667eea; text-decoration: none;">{{email}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Subject</div>
|
||||||
|
<div class="field-value">{{subject}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Message</div>
|
||||||
|
<div class="message-field">
|
||||||
|
<div class="field-value">{{message}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if fields}}
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Additional Information</div>
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
{{#each fields}}
|
||||||
|
<div style="margin-bottom: 10px; padding: 10px; background-color: #fff; border-radius: 4px; border-left: 3px solid #28a745;">
|
||||||
|
<strong>{{@key}}:</strong> {{this}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="metadata">
|
||||||
|
<h3>Submission Details</h3>
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">Submitted:</span>
|
||||||
|
<span class="metadata-value">{{date_format submitted_at "%B %d, %Y at %I:%M %p UTC"}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">Form Type:</span>
|
||||||
|
<span class="metadata-value">{{capitalize form_type}}</span>
|
||||||
|
</div>
|
||||||
|
{{#if ip_address}}
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">IP Address:</span>
|
||||||
|
<span class="metadata-value">{{ip_address}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if user_agent}}
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">User Agent:</span>
|
||||||
|
<span class="metadata-value">{{truncate user_agent 100}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>This email was generated automatically from your website contact form.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
181
templates/email/en_/html/notification.hbs
Normal file
181
templates/email/en_/html/notification.hbs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{title}}</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.header .icon {
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-left: 4px solid #007bff;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 0 6px 6px 0;
|
||||||
|
}
|
||||||
|
.message p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.additional-content {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.additional-content h3 {
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.additional-content .content-body {
|
||||||
|
color: #212529;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
}
|
||||||
|
.footer p {
|
||||||
|
margin: 0;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.timestamp {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
text-align: center;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.alert-info {
|
||||||
|
color: #0c5460;
|
||||||
|
background-color: #d1ecf1;
|
||||||
|
border-color: #bee5eb;
|
||||||
|
}
|
||||||
|
.alert-warning {
|
||||||
|
color: #856404;
|
||||||
|
background-color: #fff3cd;
|
||||||
|
border-color: #ffeaa7;
|
||||||
|
}
|
||||||
|
.alert-success {
|
||||||
|
color: #155724;
|
||||||
|
background-color: #d4edda;
|
||||||
|
border-color: #c3e6cb;
|
||||||
|
}
|
||||||
|
.alert-danger {
|
||||||
|
color: #721c24;
|
||||||
|
background-color: #f8d7da;
|
||||||
|
border-color: #f5c6cb;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.header, .content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.header .icon {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="icon">🔔</div>
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{{#if type}}
|
||||||
|
<div class="alert alert-{{type}}">
|
||||||
|
<strong>{{capitalize type}}:</strong> This is a {{type}} notification.
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="message">
|
||||||
|
<p>{{message}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if content}}
|
||||||
|
<div class="additional-content">
|
||||||
|
<h3>Additional Information</h3>
|
||||||
|
<div class="content-body">
|
||||||
|
{{{content}}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if action_url}}
|
||||||
|
<div style="text-align: center; margin: 30px 0;">
|
||||||
|
<a href="{{action_url}}" style="display: inline-block; padding: 12px 24px; background-color: #007bff; color: white; text-decoration: none; border-radius: 6px; font-weight: 600;">
|
||||||
|
{{default action_text "Take Action"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="timestamp">
|
||||||
|
<p>Sent on {{date_format (default timestamp "now") "%B %d, %Y at %I:%M %p UTC"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>This is an automated notification. Please do not reply to this email.</p>
|
||||||
|
{{#if unsubscribe_url}}
|
||||||
|
<p style="margin-top: 10px;">
|
||||||
|
<a href="{{unsubscribe_url}}" style="color: #6c757d; font-size: 12px;">Unsubscribe from notifications</a>
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
32
templates/email/en_/text/contact.hbs
Normal file
32
templates/email/en_/text/contact.hbs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
=== CONTACT FORM SUBMISSION ===
|
||||||
|
|
||||||
|
You have received a new message from your website contact form.
|
||||||
|
|
||||||
|
CONTACT DETAILS:
|
||||||
|
Name: {{name}}
|
||||||
|
Email: {{email}}
|
||||||
|
Subject: {{subject}}
|
||||||
|
|
||||||
|
MESSAGE:
|
||||||
|
{{message}}
|
||||||
|
|
||||||
|
{{#if fields}}
|
||||||
|
ADDITIONAL INFORMATION:
|
||||||
|
{{#each fields}}
|
||||||
|
{{@key}}: {{this}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
SUBMISSION DETAILS:
|
||||||
|
Submitted: {{date_format submitted_at "%B %d, %Y at %I:%M %p UTC"}}
|
||||||
|
Form Type: {{capitalize form_type}}
|
||||||
|
{{#if ip_address}}
|
||||||
|
IP Address: {{ip_address}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if user_agent}}
|
||||||
|
User Agent: {{truncate user_agent 100}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
This email was generated automatically from your website contact form.
|
||||||
|
To reply to the sender, use their email address: {{email}}
|
29
templates/email/en_/text/notification.hbs
Normal file
29
templates/email/en_/text/notification.hbs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
=== NOTIFICATION ===
|
||||||
|
|
||||||
|
{{title}}
|
||||||
|
|
||||||
|
{{#if type}}
|
||||||
|
[{{uppercase type}}] This is a {{type}} notification.
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{message}}
|
||||||
|
|
||||||
|
{{#if content}}
|
||||||
|
|
||||||
|
ADDITIONAL INFORMATION:
|
||||||
|
{{content}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if action_url}}
|
||||||
|
|
||||||
|
ACTION REQUIRED:
|
||||||
|
{{default action_text "Take Action"}}: {{action_url}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
Sent on {{date_format (default timestamp "now") "%B %d, %Y at %I:%M %p UTC"}}
|
||||||
|
|
||||||
|
This is an automated notification. Please do not reply to this email.
|
||||||
|
{{#if unsubscribe_url}}
|
||||||
|
To unsubscribe from notifications, visit: {{unsubscribe_url}}
|
||||||
|
{{/if}}
|
217
templates/email/es_/html/contact.hbs
Normal file
217
templates/email/es_/html/contact.hbs
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Formulario de Contacto Recibido</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.header p {
|
||||||
|
margin: 10px 0 0 0;
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.field {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-left: 4px solid #667eea;
|
||||||
|
}
|
||||||
|
.field-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 14px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.field-value {
|
||||||
|
color: #212529;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.message-field {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.message-field .field-value {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.metadata {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.metadata h3 {
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.metadata-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.metadata-label {
|
||||||
|
color: #6c757d;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.metadata-value {
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
}
|
||||||
|
.footer p {
|
||||||
|
margin: 0;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.highlight {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
border: 1px solid #ffeaa7;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.highlight strong {
|
||||||
|
color: #856404;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.header, .content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.metadata-item {
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.metadata-label {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>📧 Nuevo Formulario de Contacto</h1>
|
||||||
|
<p>Has recibido un nuevo mensaje desde tu sitio web</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div class="highlight">
|
||||||
|
<strong>Responde directamente a este correo</strong> para contestar al remitente, o usa la información de contacto a continuación.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Nombre</div>
|
||||||
|
<div class="field-value">{{name}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Dirección de Correo</div>
|
||||||
|
<div class="field-value">
|
||||||
|
<a href="mailto:{{email}}" style="color: #667eea; text-decoration: none;">{{email}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Asunto</div>
|
||||||
|
<div class="field-value">{{subject}}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Mensaje</div>
|
||||||
|
<div class="message-field">
|
||||||
|
<div class="field-value">{{message}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if fields}}
|
||||||
|
<div class="field">
|
||||||
|
<div class="field-label">Información Adicional</div>
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
{{#each fields}}
|
||||||
|
<div style="margin-bottom: 10px; padding: 10px; background-color: #fff; border-radius: 4px; border-left: 3px solid #28a745;">
|
||||||
|
<strong>{{@key}}:</strong> {{this}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="metadata">
|
||||||
|
<h3>Detalles del Envío</h3>
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">Enviado:</span>
|
||||||
|
<span class="metadata-value">{{date_format submitted_at "%d de %B de %Y a las %H:%M UTC"}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">Tipo de Formulario:</span>
|
||||||
|
<span class="metadata-value">{{capitalize form_type}}</span>
|
||||||
|
</div>
|
||||||
|
{{#if ip_address}}
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">Dirección IP:</span>
|
||||||
|
<span class="metadata-value">{{ip_address}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{#if user_agent}}
|
||||||
|
<div class="metadata-item">
|
||||||
|
<span class="metadata-label">Navegador:</span>
|
||||||
|
<span class="metadata-value">{{truncate user_agent 100}}</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>Este correo fue generado automáticamente desde el formulario de contacto de tu sitio web.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
181
templates/email/es_/html/notification.hbs
Normal file
181
templates/email/es_/html/notification.hbs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{title}}</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(135deg, #007bff 0%, #0056b3 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.header .icon {
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.message {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-left: 4px solid #007bff;
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 0 6px 6px 0;
|
||||||
|
}
|
||||||
|
.message p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.additional-content {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.additional-content h3 {
|
||||||
|
margin: 0 0 15px 0;
|
||||||
|
color: #495057;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.additional-content .content-body {
|
||||||
|
color: #212529;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
}
|
||||||
|
.footer p {
|
||||||
|
margin: 0;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.timestamp {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #dee2e6;
|
||||||
|
text-align: center;
|
||||||
|
color: #6c757d;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.alert-info {
|
||||||
|
color: #0c5460;
|
||||||
|
background-color: #d1ecf1;
|
||||||
|
border-color: #bee5eb;
|
||||||
|
}
|
||||||
|
.alert-warning {
|
||||||
|
color: #856404;
|
||||||
|
background-color: #fff3cd;
|
||||||
|
border-color: #ffeaa7;
|
||||||
|
}
|
||||||
|
.alert-success {
|
||||||
|
color: #155724;
|
||||||
|
background-color: #d4edda;
|
||||||
|
border-color: #c3e6cb;
|
||||||
|
}
|
||||||
|
.alert-danger {
|
||||||
|
color: #721c24;
|
||||||
|
background-color: #f8d7da;
|
||||||
|
border-color: #f5c6cb;
|
||||||
|
}
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.header, .content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.header .icon {
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="icon">🔔</div>
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{{#if type}}
|
||||||
|
<div class="alert alert-{{type}}">
|
||||||
|
<strong>{{capitalize type}}:</strong> Esta es una notificación {{type}}.
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="message">
|
||||||
|
<p>{{message}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if content}}
|
||||||
|
<div class="additional-content">
|
||||||
|
<h3>Información Adicional</h3>
|
||||||
|
<div class="content-body">
|
||||||
|
{{{content}}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if action_url}}
|
||||||
|
<div style="text-align: center; margin: 30px 0;">
|
||||||
|
<a href="{{action_url}}" style="display: inline-block; padding: 12px 24px; background-color: #007bff; color: white; text-decoration: none; border-radius: 6px; font-weight: 600;">
|
||||||
|
{{default action_text "Tomar Acción"}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="timestamp">
|
||||||
|
<p>Enviado el {{date_format (default timestamp "now") "%d de %B de %Y a las %H:%M UTC"}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>Esta es una notificación automática. Por favor no respondas a este correo.</p>
|
||||||
|
{{#if unsubscribe_url}}
|
||||||
|
<p style="margin-top: 10px;">
|
||||||
|
<a href="{{unsubscribe_url}}" style="color: #6c757d; font-size: 12px;">Cancelar suscripción de notificaciones</a>
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
32
templates/email/es_/text/contact.hbs
Normal file
32
templates/email/es_/text/contact.hbs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
=== FORMULARIO DE CONTACTO ===
|
||||||
|
|
||||||
|
Has recibido un nuevo mensaje desde el formulario de contacto de tu sitio web.
|
||||||
|
|
||||||
|
DETALLES DEL CONTACTO:
|
||||||
|
Nombre: {{name}}
|
||||||
|
Correo: {{email}}
|
||||||
|
Asunto: {{subject}}
|
||||||
|
|
||||||
|
MENSAJE:
|
||||||
|
{{message}}
|
||||||
|
|
||||||
|
{{#if fields}}
|
||||||
|
INFORMACIÓN ADICIONAL:
|
||||||
|
{{#each fields}}
|
||||||
|
{{@key}}: {{this}}
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
DETALLES DEL ENVÍO:
|
||||||
|
Enviado: {{date_format submitted_at "%d de %B de %Y a las %H:%M UTC"}}
|
||||||
|
Tipo de Formulario: {{capitalize form_type}}
|
||||||
|
{{#if ip_address}}
|
||||||
|
Dirección IP: {{ip_address}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if user_agent}}
|
||||||
|
Navegador: {{truncate user_agent 100}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
Este correo fue generado automáticamente desde el formulario de contacto de tu sitio web.
|
||||||
|
Para responder al remitente, usa su dirección de correo: {{email}}
|
29
templates/email/es_/text/notification.hbs
Normal file
29
templates/email/es_/text/notification.hbs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
=== NOTIFICACIÓN ===
|
||||||
|
|
||||||
|
{{title}}
|
||||||
|
|
||||||
|
{{#if type}}
|
||||||
|
[{{uppercase type}}] Esta es una notificación {{type}}.
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{message}}
|
||||||
|
|
||||||
|
{{#if content}}
|
||||||
|
|
||||||
|
INFORMACIÓN ADICIONAL:
|
||||||
|
{{content}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if action_url}}
|
||||||
|
|
||||||
|
ACCIÓN REQUERIDA:
|
||||||
|
{{default action_text "Tomar Acción"}}: {{action_url}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
---
|
||||||
|
Enviado el {{date_format (default timestamp "now") "%d de %B de %Y a las %H:%M UTC"}}
|
||||||
|
|
||||||
|
Esta es una notificación automática. Por favor no respondas a este correo.
|
||||||
|
{{#if unsubscribe_url}}
|
||||||
|
Para cancelar la suscripción de notificaciones, visita: {{unsubscribe_url}}
|
||||||
|
{{/if}}
|
361
templates/page.html
Normal file
361
templates/page.html
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{lang | default(value='en')}}">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{title}} - {{site_name | default(value="My Website")}}</title>
|
||||||
|
<meta name="description" content="{{description | default(value=content | excerpt(length=160))}}">
|
||||||
|
{% if author %}
|
||||||
|
<meta name="author" content="{{author}}">
|
||||||
|
{% endif %}
|
||||||
|
{% if keywords %}
|
||||||
|
<meta name="keywords" content="{{keywords | join(sep=', ')}}">
|
||||||
|
{% endif %}
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 2rem 0;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.header .subtitle {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
.main-content {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 300px;
|
||||||
|
gap: 40px;
|
||||||
|
margin: 40px auto;
|
||||||
|
max-width: 1200px;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
background: white;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
|
.content h2 {
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
border-bottom: 2px solid #3498db;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
.content h3 {
|
||||||
|
color: #34495e;
|
||||||
|
margin: 30px 0 15px 0;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
.content p {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
.content ul, .content ol {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-left: 30px;
|
||||||
|
}
|
||||||
|
.content li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
.content blockquote {
|
||||||
|
border-left: 4px solid #3498db;
|
||||||
|
padding-left: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-style: italic;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.content code {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: 'Consolas', 'Monaco', monospace;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.content pre {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.content pre code {
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
background: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||||
|
height: fit-content;
|
||||||
|
position: sticky;
|
||||||
|
top: 20px;
|
||||||
|
}
|
||||||
|
.sidebar h3 {
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
.sidebar ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.sidebar li {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.sidebar a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.sidebar a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.meta-info {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.meta-info strong {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.breadcrumbs {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 15px 0;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.breadcrumbs a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.breadcrumbs a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.breadcrumbs span {
|
||||||
|
color: #666;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background: #2c3e50;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 0;
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
.footer p {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #3498db;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.cta-section {
|
||||||
|
background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 40px 0;
|
||||||
|
}
|
||||||
|
.cta-section h3 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.cta-section p {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
.cta-button {
|
||||||
|
display: inline-block;
|
||||||
|
background: white;
|
||||||
|
color: #3498db;
|
||||||
|
padding: 15px 30px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 600;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
.cta-button:hover {
|
||||||
|
background: #f8f9fa;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.main-content {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
.content, .sidebar {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
.header .subtitle {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% if breadcrumbs %}
|
||||||
|
<div class="breadcrumbs">
|
||||||
|
<div class="container">
|
||||||
|
{% for crumb in breadcrumbs %}
|
||||||
|
{% if not loop.last %}
|
||||||
|
<a href="{{crumb.url}}">{{crumb.title}}</a>
|
||||||
|
<span>></span>
|
||||||
|
{% else %}
|
||||||
|
<span>{{crumb.title}}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<header class="header">
|
||||||
|
<div class="container">
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
{% if subtitle %}
|
||||||
|
<p class="subtitle">{{subtitle}}</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
|
<main class="content">
|
||||||
|
{% if show_meta %}
|
||||||
|
<div class="meta-info">
|
||||||
|
{% if last_updated %}
|
||||||
|
<strong>Last Updated:</strong> {{last_updated | date_format(format="%B %d, %Y")}}
|
||||||
|
{% endif %}
|
||||||
|
{% if author %}
|
||||||
|
<br><strong>Author:</strong> {{author}}
|
||||||
|
{% endif %}
|
||||||
|
{% if reading_time %}
|
||||||
|
<br><strong>Reading Time:</strong> {{reading_time}} minutes
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if featured_image %}
|
||||||
|
<img src="{{featured_image}}" alt="{{title}}" style="width: 100%; height: auto; margin-bottom: 30px; border-radius: 5px;">
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{content | markdown | safe}}
|
||||||
|
|
||||||
|
{% if cta_enabled %}
|
||||||
|
<div class="cta-section">
|
||||||
|
<h3>{{cta_title | default(value="Ready to Get Started?")}}</h3>
|
||||||
|
<p>{{cta_description | default(value="Take the next step and explore what we have to offer.")}}</p>
|
||||||
|
<a href="{{cta_url | default(value='/contact')}}" class="cta-button">{{cta_button_text | default(value="Get Started")}}</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<aside class="sidebar">
|
||||||
|
{% if toc_enabled and toc %}
|
||||||
|
<h3>Table of Contents</h3>
|
||||||
|
<ul>
|
||||||
|
{% for item in toc %}
|
||||||
|
<li><a href="#{{item.anchor}}">{{item.title}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if sidebar_links %}
|
||||||
|
<h3>{{sidebar_title | default(value="Quick Links")}}</h3>
|
||||||
|
<ul>
|
||||||
|
{% for link in sidebar_links %}
|
||||||
|
<li><a href="{{link.url}}">{{link.title}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if contact_info %}
|
||||||
|
<h3>Contact Information</h3>
|
||||||
|
<div class="meta-info">
|
||||||
|
{% if contact_info.email %}
|
||||||
|
<strong>Email:</strong> <a href="mailto:{{contact_info.email}}">{{contact_info.email}}</a><br>
|
||||||
|
{% endif %}
|
||||||
|
{% if contact_info.phone %}
|
||||||
|
<strong>Phone:</strong> {{contact_info.phone}}<br>
|
||||||
|
{% endif %}
|
||||||
|
{% if contact_info.address %}
|
||||||
|
<strong>Address:</strong> {{contact_info.address}}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if related_pages %}
|
||||||
|
<h3>Related Pages</h3>
|
||||||
|
<ul>
|
||||||
|
{% for page in related_pages %}
|
||||||
|
<li><a href="{{page.url}}">{{page.title}}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div class="container">
|
||||||
|
<p>© {{current_year | default(value="2024")}} {{site_name | default(value="My Website")}}. All rights reserved.</p>
|
||||||
|
{% if footer_links %}
|
||||||
|
<p>
|
||||||
|
{% for link in footer_links %}
|
||||||
|
<a href="{{link.url}}">{{link.title}}</a>
|
||||||
|
{% if not loop.last %} | {% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
{% if analytics_id %}
|
||||||
|
<script>
|
||||||
|
// Add analytics tracking here if needed
|
||||||
|
console.log('Analytics ID: {{analytics_id}}');
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
x
Reference in New Issue
Block a user