Files
citrus/resources/views/filament/components/markdown-preview.blade.php
T

237 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@php
$accent = $get('meta.accent_color') ?? 'indigo';
$accentColor = match($accent) {
'emerald' => '#059669',
'cyberpunk' => '#ec4899',
'coral' => '#ea580c',
'amber' => '#d97706',
default => '#4f46e5',
};
$accentGradient = match($accent) {
'emerald' => 'linear-gradient(135deg, #059669 0%, #10b981 100%)',
'cyberpunk' => 'linear-gradient(135deg, #ec4899 0%, #f43f5e 100%)',
'coral' => 'linear-gradient(135deg, #ea580c 0%, #f97316 100%)',
'amber' => 'linear-gradient(135deg, #d97706 0%, #f59e0b 100%)',
default => 'linear-gradient(135deg, #4f46e5 0%, #6366f1 100%)',
};
$uid = 'mdprev_' . uniqid();
@endphp
{{-- Google Fonts --}}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;500;600;700;800&display=swap" rel="stylesheet">
{{-- Marked.js CDN --}}
<script src="https://cdn.jsdelivr.net/npm/marked@9/marked.min.js"></script>
<div id="{{ $uid }}" style="font-family: 'Inter', system-ui, sans-serif;">
{{-- Browser Chrome --}}
<div style="border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 24px rgba(0,0,0,0.08); background: #f8fafc; height: 700px; display: flex; flex-direction: column;">
{{-- Title Bar --}}
<div style="background: #f1f5f9; border-bottom: 1px solid #e2e8f0; padding: 10px 16px; display: flex; align-items: center; gap: 12px; flex-shrink: 0;">
<div style="display: flex; gap: 6px; flex-shrink: 0;">
<span style="width: 12px; height: 12px; border-radius: 50%; background: #ff5f57; display:inline-block;"></span>
<span style="width: 12px; height: 12px; border-radius: 50%; background: #febc2e; display:inline-block;"></span>
<span style="width: 12px; height: 12px; border-radius: 50%; background: #28c840; display:inline-block;"></span>
</div>
<div style="flex: 1; max-width: 480px; margin: 0 auto; background: white; border: 1px solid #e2e8f0; border-radius: 6px; padding: 5px 10px; display: flex; align-items: center; gap: 6px; font-size: 12px; color: #94a3b8;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#22c55e" style="width:14px;height:14px;flex-shrink:0;">
<path fill-rule="evenodd" d="M10 1a4.5 4.5 0 00-4.5 4.5V9H5a2 2 0 00-2 2v6a2 2 0 002 2h10a2 2 0 002-2v-6a2 2 0 00-2-2h-.5V5.5A4.5 4.5 0 0010 1zm3 8V5.5a3 3 0 10-6 0V9h6z" clip-rule="evenodd"/>
</svg>
<span style="font-family: monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
truncgil.com/teklif/<strong style="color: #334155;">{{ $get('slug') ?: '...' }}</strong>
</span>
</div>
<div style="width: 60px; flex-shrink: 0;"></div>
</div>
{{-- Page Body --}}
<div style="flex: 1; overflow-y: auto; background: #f1f5f9; padding: 24px;">
<div style="max-width: 800px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); border: 1px solid #e5e7eb; overflow: hidden;">
{{-- Accent stripe --}}
<div style="height: 4px; background: {{ $accentGradient }};"></div>
{{-- Document --}}
<div style="padding: 32px 40px;">
{{-- Header --}}
<div style="margin-bottom: 24px; padding-bottom: 20px; border-bottom: 1px solid #f1f5f9;">
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 10px;">
<span style="font-size: 9px; text-transform: uppercase; letter-spacing: 1.5px; font-weight: 800; padding: 3px 8px; border-radius: 4px; color: white; background: {{ $accentColor }};">TEKNİK VE MALİ TEKLİF</span>
@if($get('client_name'))
<span style="font-size: 11px; background: #f8fafc; color: #64748b; font-weight: 600; padding: 3px 8px; border-radius: 4px; border: 1px solid #e2e8f0;">{{ $get('client_name') }}</span>
@endif
</div>
<h1 style="font-family: 'Outfit', sans-serif; font-size: 22px; font-weight: 800; color: #0f172a; margin: 0 0 8px 0; line-height: 1.3;">{{ $get('title') ?: 'Teklif Başlığı' }}</h1>
<div style="font-size: 11px; color: #94a3b8; font-weight: 500; display: flex; gap: 12px; flex-wrap: wrap;">
<span>REF: {{ $get('slug') ?: '—' }}</span>
<span>•</span>
<span style="font-weight: 700; color: #334155;">{{ $get('total_price') ? number_format((float) $get('total_price'), 2, ',', '.') : '—' }} {{ $get('currency') ?: 'TRY' }}</span>
<span>•</span>
<span>Geçerlilik: {{ $get('valid_until') ? date('d.m.Y', strtotime($get('valid_until'))) : '—' }}</span>
</div>
</div>
{{-- Markdown Output (plain div, updated by vanilla JS) --}}
<div id="{{ $uid }}_placeholder" style="text-align:center; padding: 60px 0; color: #94a3b8; font-style: italic; font-size: 14px;">
✏️ Sol taraftaki editöre Markdown yazın, canlı önizleme burada görünecektir.
</div>
<div id="{{ $uid }}_body" class="mdprev-body" style="display:none;"></div>
</div>
</div>
</div>
</div>
</div>
<script>
(function() {
var uid = '{{ $uid }}';
var bodyEl = null;
var phEl = null;
var lastContent = null;
function getBodyEl() {
if (!bodyEl) bodyEl = document.getElementById(uid + '_body');
return bodyEl;
}
function getPhEl() {
if (!phEl) phEl = document.getElementById(uid + '_placeholder');
return phEl;
}
function readEditorContent() {
// Method 1: Read from CodeMirror 6 .cm-content
var cmContents = document.querySelectorAll('.cm-content');
for (var i = 0; i < cmContents.length; i++) {
var text = cmContents[i].innerText || cmContents[i].textContent;
if (text && text.trim().length > 0) return text;
}
// Method 2: Livewire data via wire:model textarea (hidden)
var textareas = document.querySelectorAll('textarea[wire\\:model], textarea[wire\\:model\\.live]');
for (var j = 0; j < textareas.length; j++) {
var ta = textareas[j];
if ((ta.name && ta.name.indexOf('content') !== -1) || (ta.id && ta.id.indexOf('content') !== -1)) {
if (ta.value && ta.value.trim()) return ta.value;
}
}
return '';
}
function renderMarkdown(content) {
var body = getBodyEl();
var ph = getPhEl();
if (!body || !ph) return;
if (!content || !content.trim()) {
body.style.display = 'none';
ph.style.display = 'block';
return;
}
if (content === lastContent) return;
lastContent = content;
if (typeof marked === 'undefined') return;
try {
var html = marked.parse(content, { gfm: true, breaks: true });
body.innerHTML = html;
body.style.display = 'block';
ph.style.display = 'none';
} catch(e) {
body.innerHTML = '<p style="color:red;">Markdown parse error: ' + e.message + '</p>';
body.style.display = 'block';
ph.style.display = 'none';
}
}
function poll() {
renderMarkdown(readEditorContent());
}
// Start polling once DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setInterval(poll, 400);
});
} else {
setInterval(poll, 400);
}
// Also hook into Livewire updates
document.addEventListener('livewire:morph', function() {
setTimeout(poll, 100);
});
})();
</script>
<style>
.mdprev-body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
font-size: 14px;
line-height: 1.7;
color: #334155;
}
.mdprev-body h1 {
font-family: 'Outfit', 'Inter', sans-serif;
font-size: 1.5rem; font-weight: 800; color: #0f172a;
margin: 2rem 0 0.8rem; line-height: 1.25; letter-spacing: -0.02em;
}
.mdprev-body h2 {
font-family: 'Outfit', 'Inter', sans-serif;
font-size: 1.25rem; font-weight: 700; color: #1e293b;
margin: 1.8rem 0 0.7rem; padding-bottom: 0.5rem;
border-bottom: 1px solid #f1f5f9; line-height: 1.3;
}
.mdprev-body h3 {
font-family: 'Outfit', 'Inter', sans-serif;
font-size: 1.1rem; font-weight: 600; color: #334155;
margin: 1.5rem 0 0.5rem;
}
.mdprev-body h4 {
font-size: 1rem; font-weight: 600; color: #475569;
margin: 1.2rem 0 0.4rem;
}
.mdprev-body p { margin: 0 0 1rem; color: #475569; }
.mdprev-body a { color: {{ $accentColor }}; text-underline-offset: 2px; }
.mdprev-body strong { font-weight: 700; color: #1e293b; }
.mdprev-body em { font-style: italic; }
.mdprev-body img { max-width: 100%; border-radius: 8px; margin: 1rem 0; display: block; }
.mdprev-body hr { border: 0; height: 1px; background: #e2e8f0; margin: 1.8rem 0; }
.mdprev-body ul { list-style-type: disc; padding-left: 1.5rem; margin: 0 0 1rem; }
.mdprev-body ol { list-style-type: decimal; padding-left: 1.5rem; margin: 0 0 1rem; }
.mdprev-body li { margin-bottom: 0.3rem; color: #475569; line-height: 1.6; }
.mdprev-body table {
width: 100%; border-collapse: collapse; margin: 1.5rem 0;
font-size: 13px; border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden;
}
.mdprev-body th {
background: #f8fafc; color: #0f172a; font-weight: 600;
text-align: left; padding: 10px 14px; border-bottom: 2px solid #e2e8f0;
}
.mdprev-body td { padding: 10px 14px; border-bottom: 1px solid #f1f5f9; color: #475569; }
.mdprev-body tr:nth-child(even) td { background: #fafbfc; }
.mdprev-body tr:last-child td { border-bottom: none; }
.mdprev-body code {
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
font-size: 0.85em; padding: 2px 6px; border-radius: 4px;
background: #f1f5f9; color: #e11d48;
}
.mdprev-body pre {
background: #0f172a; border-radius: 8px;
padding: 16px; overflow-x: auto; margin: 1rem 0;
}
.mdprev-body pre code { background: transparent; color: #e2e8f0; padding: 0; font-size: 13px; }
.mdprev-body blockquote {
border-left: 3px solid {{ $accentColor }}; margin: 1rem 0;
padding: 0.5rem 0 0.5rem 1rem; color: #64748b;
background: #f8fafc; border-radius: 0 6px 6px 0;
}
.mdprev-body blockquote p { margin: 0; }
</style>