Files
php-flasher/demo/symfony/templates/playground.html.twig
T
2026-03-01 22:47:28 +00:00

267 lines
13 KiB
Twig

{% extends 'base.html.twig' %}
{% block title %}Playground{% endblock %}
{% block content %}
<div class="mb-8">
<h1 class="section-title">Interactive Playground</h1>
<p class="section-subtitle">Build and customize notifications in real-time. See the generated PHP code instantly.</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
{# Configuration Panel #}
<div class="card">
<div class="card-header">
<h2 class="text-xl font-bold text-gray-800">Configuration</h2>
</div>
<div class="card-body space-y-6">
{# Type #}
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Notification Type</label>
<div class="grid grid-cols-4 gap-2">
<button onclick="setType('success')" id="type-success" class="type-btn px-3 py-2 rounded-lg border-2 border-emerald-500 bg-emerald-50 text-emerald-700 font-medium text-sm">
Success
</button>
<button onclick="setType('error')" id="type-error" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-rose-500 hover:bg-rose-50 hover:text-rose-700">
Error
</button>
<button onclick="setType('warning')" id="type-warning" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-amber-500 hover:bg-amber-50 hover:text-amber-700">
Warning
</button>
<button onclick="setType('info')" id="type-info" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-sky-500 hover:bg-sky-50 hover:text-sky-700">
Info
</button>
</div>
</div>
{# Title #}
<div>
<label for="title" class="block text-sm font-medium text-gray-700 mb-2">Title (optional)</label>
<input type="text" id="title" placeholder="Enter a title..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
oninput="updateCode()">
</div>
{# Message #}
<div>
<label for="message" class="block text-sm font-medium text-gray-700 mb-2">Message</label>
<textarea id="message" rows="2" placeholder="Enter your notification message..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
oninput="updateCode()">Operation completed successfully!</textarea>
</div>
{# Position #}
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Position</label>
<select id="position" onchange="updateCode()"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
<option value="top-right" selected>Top Right (default)</option>
<option value="top-left">Top Left</option>
<option value="top-center">Top Center</option>
<option value="bottom-right">Bottom Right</option>
<option value="bottom-left">Bottom Left</option>
<option value="bottom-center">Bottom Center</option>
<option value="center">Center</option>
</select>
</div>
{# Theme #}
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Theme</label>
<select id="theme" onchange="updateCode()"
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
<option value="">Default (Flasher)</option>
<option value="flasher">Flasher</option>
<option value="material">Material</option>
<option value="ios">iOS</option>
<option value="slack">Slack</option>
<option value="amazon">Amazon</option>
<option value="google">Google</option>
</select>
</div>
{# Timeout #}
<div>
<label for="timeout" class="block text-sm font-medium text-gray-700 mb-2">
Timeout: <span id="timeout-value">5000</span>ms
</label>
<input type="range" id="timeout" min="1000" max="10000" step="500" value="5000"
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
oninput="document.getElementById('timeout-value').textContent = this.value; updateCode()">
</div>
{# Show Button #}
<button onclick="showPlaygroundNotification()" class="btn btn-primary w-full">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
Show Notification
</button>
</div>
</div>
{# Code Preview #}
<div class="space-y-6">
<div class="card">
<div class="card-header flex justify-between items-center">
<h2 class="text-xl font-bold text-gray-800">Generated Code</h2>
<button onclick="copyCode()" class="btn btn-sm btn-outline">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
</svg>
Copy
</button>
</div>
<div class="card-body p-0">
<div class="code-block !my-0 !rounded-none">
<div class="code-header">
<span>PHP</span>
</div>
<pre class="!m-0"><code class="language-php" id="generated-code">flash()->success('Operation completed successfully!');</code></pre>
</div>
</div>
</div>
{# Preview Card #}
<div class="card">
<div class="card-header">
<h2 class="text-xl font-bold text-gray-800">Preview</h2>
</div>
<div class="card-body">
<div class="bg-gray-100 rounded-lg p-6 min-h-[200px] flex items-center justify-center">
<div id="preview-notification" class="max-w-sm w-full">
<div class="bg-emerald-500 text-white p-4 rounded-lg shadow-lg">
<div class="flex items-start space-x-3">
<svg class="w-6 h-6 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<div>
<p id="preview-title" class="font-semibold hidden"></p>
<p id="preview-message" class="text-sm opacity-90">Operation completed successfully!</p>
</div>
</div>
</div>
</div>
</div>
<p class="text-sm text-gray-500 mt-3 text-center">This is a static preview. Click "Show Notification" to see the real notification.</p>
</div>
</div>
</div>
</div>
{% endblock %}
{% block javascripts %}
<script>
let currentType = 'success';
const typeColors = {
success: { border: 'border-emerald-500', bg: 'bg-emerald-50', text: 'text-emerald-700', preview: 'bg-emerald-500' },
error: { border: 'border-rose-500', bg: 'bg-rose-50', text: 'text-rose-700', preview: 'bg-rose-500' },
warning: { border: 'border-amber-500', bg: 'bg-amber-50', text: 'text-amber-700', preview: 'bg-amber-500' },
info: { border: 'border-sky-500', bg: 'bg-sky-50', text: 'text-sky-700', preview: 'bg-sky-500' }
};
function setType(type) {
currentType = type;
document.querySelectorAll('.type-btn').forEach(btn => {
btn.className = 'type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm';
});
const activeBtn = document.getElementById(`type-${type}`);
const colors = typeColors[type];
activeBtn.className = `type-btn px-3 py-2 rounded-lg border-2 ${colors.border} ${colors.bg} ${colors.text} font-medium text-sm`;
updatePreview();
updateCode();
}
function updatePreview() {
const previewDiv = document.querySelector('#preview-notification > div');
const colors = typeColors[currentType];
previewDiv.className = `${colors.preview} text-white p-4 rounded-lg shadow-lg`;
const title = document.getElementById('title').value;
const message = document.getElementById('message').value;
document.getElementById('preview-title').textContent = title;
document.getElementById('preview-title').classList.toggle('hidden', !title);
document.getElementById('preview-message').textContent = message || 'Your notification message...';
}
function updateCode() {
const type = currentType;
const title = document.getElementById('title').value;
const message = document.getElementById('message').value || 'Your message here';
const position = document.getElementById('position').value;
const theme = document.getElementById('theme').value;
const timeout = document.getElementById('timeout').value;
let code = '';
const hasOptions = position !== 'top-right' || timeout !== '5000';
if (theme) {
code = `flash()->use('theme.${theme}')`;
} else {
code = 'flash()';
}
if (hasOptions) {
const options = [];
if (position !== 'top-right') {
options.push(`'position' => '${position}'`);
}
if (timeout !== '5000') {
options.push(`'timeout' => ${timeout}`);
}
if (title) {
code += `\n ->${type}('${message}', '${title}', [${options.join(', ')}]);`;
} else {
code += `\n ->${type}('${message}', [${options.join(', ')}]);`;
}
} else {
if (title) {
code += `->${type}('${message}', '${title}');`;
} else {
code += `->${type}('${message}');`;
}
}
document.getElementById('generated-code').textContent = code;
Prism.highlightElement(document.getElementById('generated-code'));
updatePreview();
}
function showPlaygroundNotification() {
const options = {
type: currentType,
message: document.getElementById('message').value || 'Your message here',
title: document.getElementById('title').value || undefined,
position: document.getElementById('position').value,
theme: document.getElementById('theme').value || undefined,
timeout: parseInt(document.getElementById('timeout').value)
};
showNotification(options);
}
function copyCode() {
const code = document.getElementById('generated-code').textContent;
navigator.clipboard.writeText(code).then(() => {
const btn = event.target.closest('button');
const originalText = btn.innerHTML;
btn.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> Copied!';
setTimeout(() => {
btn.innerHTML = originalText;
}, 2000);
});
}
document.addEventListener('DOMContentLoaded', function() {
updateCode();
});
</script>
{% endblock %}