feat: ui polish, docs, api hardening, and common pages
This commit is contained in:
@@ -3,6 +3,29 @@
|
||||
@section('title', 'API Docs - Dewemoji')
|
||||
@section('meta_description', 'Dewemoji API docs for emoji search, categories, license verification, activation, and system endpoints.')
|
||||
|
||||
@push('head')
|
||||
<style>
|
||||
.doc-table tbody tr { border-bottom: 1px solid rgba(148,163,184,0.2); }
|
||||
.doc-table tbody tr:hover { background: rgba(32,83,255,0.08); }
|
||||
.codewrap { position: relative; }
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
top: .5rem;
|
||||
right: .5rem;
|
||||
font-size: .7rem;
|
||||
padding: .2rem .45rem;
|
||||
border-radius: .375rem;
|
||||
border: 1px solid rgba(255,255,255,0.15);
|
||||
background: rgba(15, 15, 20, 0.7);
|
||||
color: #e5e7eb;
|
||||
}
|
||||
.copy-btn:hover { background: rgba(32,83,255,0.35); }
|
||||
@media (max-width: 1023px) {
|
||||
#toc-aside { position: static !important; top: auto !important; }
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@push('jsonld')
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -16,27 +39,335 @@
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 py-10">
|
||||
<h1 class="font-display text-4xl font-bold">API Docs</h1>
|
||||
<p class="text-gray-400 mt-2">Base URL: <code>{{ url('/v1') }}</code></p>
|
||||
<div class="flex h-screen w-full">
|
||||
<aside class="hidden lg:flex w-20 lg:w-64 h-full glass-panel flex-col justify-between p-4 z-50 shrink-0">
|
||||
<div>
|
||||
<div class="flex items-center gap-3 px-2 mb-8 mt-2">
|
||||
<div class="w-10 h-10 rounded-xl bg-gradient-to-br from-white to-gray-300 flex items-center justify-center shadow-lg shadow-white/20 shrink-0">
|
||||
<img src="/assets/logo/logo-mark.svg" alt="Dewemoji logo" class="w-7 h-7 object-contain" />
|
||||
</div>
|
||||
<h1 class="font-display font-bold text-lg tracking-tight hidden lg:block">Dewemoji</h1>
|
||||
</div>
|
||||
<nav class="space-y-1">
|
||||
<a href="{{ route('home') }}" class="flex items-center gap-4 px-3 py-3 rounded-xl text-gray-400 hover:text-white hover:bg-white/5 transition-all"><i data-lucide="layout-grid" class="w-5 h-5"></i><span class="text-sm hidden lg:block">Discover</span></a>
|
||||
<a href="{{ route('api-docs') }}" class="flex items-center gap-4 px-3 py-3 rounded-xl bg-white/10 text-brand-sun border border-white/5 transition-all"><i data-lucide="book-open" class="w-5 h-5"></i><span class="text-sm hidden lg:block">API Docs</span></a>
|
||||
<a href="{{ route('pricing') }}" class="flex items-center gap-4 px-3 py-3 rounded-xl text-gray-400 hover:text-white hover:bg-white/5 transition-all"><i data-lucide="badge-dollar-sign" class="w-5 h-5"></i><span class="text-sm hidden lg:block">Pricing</span></a>
|
||||
<a href="{{ route('support') }}" class="flex items-center gap-4 px-3 py-3 rounded-xl text-gray-400 hover:text-white hover:bg-white/5 transition-all"><i data-lucide="life-buoy" class="w-5 h-5"></i><span class="text-sm hidden lg:block">Support</span></a>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<a href="{{ route('privacy') }}" class="flex items-center gap-4 px-3 py-3 rounded-xl text-gray-400 hover:text-white hover:bg-white/5 transition-all"><i data-lucide="shield-check" class="w-5 h-5"></i><span class="text-sm hidden lg:block">Privacy</span></a>
|
||||
<a href="{{ route('terms') }}" class="flex items-center gap-4 px-3 py-3 rounded-xl text-gray-400 hover:text-white hover:bg-white/5 transition-all"><i data-lucide="file-text" class="w-5 h-5"></i><span class="text-sm hidden lg:block">Terms</span></a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="glass-card rounded-2xl p-5 mt-6">
|
||||
<h2 class="text-lg font-semibold">Core endpoints</h2>
|
||||
<ul class="mt-3 space-y-1 text-sm text-gray-300">
|
||||
<li><code>GET /v1/categories</code></li>
|
||||
<li><code>GET /v1/emojis?q=<term>&category=<label>&subcategory=<slug></code></li>
|
||||
<li><code>GET /v1/emoji/{slug}</code> or <code>/v1/emoji?slug=</code></li>
|
||||
<li><code>POST /v1/license/verify</code></li>
|
||||
<li><code>POST /v1/license/activate</code></li>
|
||||
<li><code>POST /v1/license/deactivate</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
<main class="flex-1 flex flex-col h-full min-w-0 relative z-10">
|
||||
<header class="glass-header px-6 py-5 shrink-0">
|
||||
<div class="text-[11px] uppercase tracking-wider text-gray-500 mb-1">Public / Documentation</div>
|
||||
<h1 class="font-display text-2xl md:text-3xl font-bold">API Documentation</h1>
|
||||
</header>
|
||||
|
||||
<div class="glass-card rounded-2xl p-5 mt-4">
|
||||
<h2 class="text-lg font-semibold">Auth</h2>
|
||||
<p class="text-sm text-gray-300 mt-2">Use <code>Authorization: Bearer YOUR_LICENSE_KEY</code> (preferred) or <code>X-License-Key</code>.</p>
|
||||
<pre class="mt-3 text-xs overflow-x-auto bg-black/30 rounded-lg p-3"><code>curl -H "Authorization: Bearer YOUR_LICENSE_KEY" \
|
||||
"{{ url('/v1/emojis') }}?q=love&limit=50&page=1"</code></pre>
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto p-6 md:p-10">
|
||||
<div id="docs-wrap" class="max-w-6xl mx-auto grid grid-cols-1 lg:grid-cols-12 gap-8 items-start">
|
||||
<aside id="toc-aside" class="lg:col-span-3 self-start sticky top-28">
|
||||
<nav class="space-y-2 text-sm">
|
||||
<p class="uppercase tracking-wide text-gray-500 font-semibold mb-2">On this page</p>
|
||||
<a href="#overview" class="block px-3 py-2 rounded hover:bg-white/5">Overview</a>
|
||||
<a href="#auth" class="block px-3 py-2 rounded hover:bg-white/5">Authentication</a>
|
||||
<a href="#plans" class="block px-3 py-2 rounded hover:bg-white/5">Plans & limits</a>
|
||||
<a href="#endpoints" class="block px-3 py-2 rounded hover:bg-white/5">Endpoints</a>
|
||||
<a href="#try-it" class="block px-3 py-2 rounded hover:bg-white/5">Try it</a>
|
||||
<a href="#errors" class="block px-3 py-2 rounded hover:bg-white/5">Errors & caching</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<section class="lg:col-span-9 space-y-8">
|
||||
<section id="overview" class="glass-card rounded-2xl p-6 scroll-mt-28">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<h2 class="font-display text-2xl font-bold">Emoji API Docs</h2>
|
||||
<span id="pro-badge" class="hidden text-[10px] font-semibold px-2 py-1 rounded bg-emerald-500/20 text-emerald-300 border border-emerald-400/40">Pro mode</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-300">Read-only API with search, categories, and emoji detail. Responses are cacheable and include ETag.</p>
|
||||
<div class="codewrap mt-4">
|
||||
<button class="copy-btn" data-copy-target="base-url-code">Copy</button>
|
||||
<pre class="text-xs overflow-x-auto bg-black/30 rounded-lg p-3"><code id="base-url-code">{{ url('/v1') }}</code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="auth" class="glass-card rounded-2xl p-6 scroll-mt-28">
|
||||
<h3 class="text-lg font-semibold">Authentication</h3>
|
||||
<p class="text-sm text-gray-300 mt-2">Free tier is public with daily caps. Pro unlocks higher limits with license key.</p>
|
||||
<div class="mt-3 space-y-3">
|
||||
<div class="codewrap">
|
||||
<button class="copy-btn" data-copy-target="auth-bearer">Copy</button>
|
||||
<pre class="text-xs overflow-x-auto bg-black/30 rounded-lg p-3"><code id="auth-bearer">Authorization: Bearer YOUR_LICENSE_KEY</code></pre>
|
||||
</div>
|
||||
<div class="codewrap">
|
||||
<button class="copy-btn" data-copy-target="auth-query">Copy</button>
|
||||
<pre class="text-xs overflow-x-auto bg-black/30 rounded-lg p-3"><code id="auth-query">?key=YOUR_LICENSE_KEY</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="mt-3 list-disc pl-5 text-sm text-gray-300 space-y-1">
|
||||
<li><code>Authorization</code> (recommended)</li>
|
||||
<li><code>X-License-Key</code> (also supported)</li>
|
||||
<li><code>X-Account-Id</code> (optional usage association)</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="plans" class="glass-card rounded-2xl p-6 scroll-mt-28">
|
||||
<h3 class="text-lg font-semibold">Plans & limits</h3>
|
||||
<div class="overflow-x-auto mt-3">
|
||||
<table class="min-w-full text-sm doc-table">
|
||||
<thead>
|
||||
<tr class="text-left text-gray-400">
|
||||
<th class="py-2 pr-6">Tier</th>
|
||||
<th class="py-2 pr-6 text-right">Page size cap</th>
|
||||
<th class="py-2 pr-6 text-right">Daily cap</th>
|
||||
<th class="py-2">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="align-top text-gray-200">
|
||||
<tr>
|
||||
<td class="py-2 pr-6"><strong>Free</strong></td>
|
||||
<td class="py-2 pr-6 text-right">20</td>
|
||||
<td class="py-2 pr-6 text-right">~30 (page-1, distinct)</td>
|
||||
<td class="py-2">Cached responses do not count.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-2 pr-6"><strong>Pro</strong></td>
|
||||
<td class="py-2 pr-6 text-right">50</td>
|
||||
<td class="py-2 pr-6 text-right">5,000 / day / license</td>
|
||||
<td class="py-2">Up to 3 Chrome profiles.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="endpoints" class="glass-card rounded-2xl p-6 scroll-mt-28">
|
||||
<h3 class="text-lg font-semibold mb-3">Endpoints</h3>
|
||||
<ul class="list-disc pl-5 text-sm text-gray-300 space-y-1">
|
||||
<li><code>/emojis</code> — search & paginate</li>
|
||||
<li><code>/emoji?slug=<slug></code> — single emoji (query)</li>
|
||||
<li><code>/emoji/<slug></code> — single emoji (pretty URL)</li>
|
||||
<li><code>/categories</code> — category map</li>
|
||||
<li><code>/license/verify</code> — license check</li>
|
||||
<li><code>/license/activate</code> — bind profile</li>
|
||||
<li><code>/license/deactivate</code> — unbind profile</li>
|
||||
</ul>
|
||||
|
||||
<div class="mt-5">
|
||||
<h4 class="font-semibold">GET <code>/emojis</code></h4>
|
||||
<p class="text-sm text-gray-300">Search across name, category, aliases, and EN/ID keywords.</p>
|
||||
<div class="overflow-x-auto mt-3">
|
||||
<table class="min-w-full text-sm doc-table">
|
||||
<thead>
|
||||
<tr class="text-left text-gray-400">
|
||||
<th class="py-2 pr-6">Query Param</th>
|
||||
<th class="py-2 pr-6">Type</th>
|
||||
<th class="py-2 pr-6">Description</th>
|
||||
<th class="py-2">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="align-top text-gray-200">
|
||||
<tr><td class="py-2 pr-6"><code>q</code> / <code>query</code></td><td class="py-2 pr-6">string</td><td class="py-2 pr-6">Keyword search (AND match).</td><td class="py-2"><em>empty</em></td></tr>
|
||||
<tr><td class="py-2 pr-6"><code>category</code></td><td class="py-2 pr-6">string</td><td class="py-2 pr-6">Top-level category label.</td><td class="py-2"><code>all</code></td></tr>
|
||||
<tr><td class="py-2 pr-6"><code>subcategory</code></td><td class="py-2 pr-6">string</td><td class="py-2 pr-6">Subcategory slug.</td><td class="py-2"><em>empty</em></td></tr>
|
||||
<tr><td class="py-2 pr-6"><code>page</code></td><td class="py-2 pr-6">number</td><td class="py-2 pr-6">1-based page.</td><td class="py-2"><code>1</code></td></tr>
|
||||
<tr><td class="py-2 pr-6"><code>limit</code></td><td class="py-2 pr-6">number</td><td class="py-2 pr-6">Items per page (max 50).</td><td class="py-2"><code>20</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="codewrap mt-3">
|
||||
<button class="copy-btn" data-copy-target="ex-curl-emojis">Copy</button>
|
||||
<pre class="text-xs overflow-x-auto bg-black/30 rounded-lg p-3"><code id="ex-curl-emojis">curl "<BASE_URL>/emojis?q=love&category=Smileys%20%26%20Emotion&limit=20&page=1"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 border-t border-white/10 pt-6">
|
||||
<h4 class="font-semibold">GET <code>/emoji</code> and <code>/emoji/<slug></code></h4>
|
||||
<div class="codewrap mt-3">
|
||||
<button class="copy-btn" data-copy-target="ex-curl-emoji">Copy</button>
|
||||
<pre class="text-xs overflow-x-auto bg-black/30 rounded-lg p-3"><code id="ex-curl-emoji">curl "<BASE_URL>/emoji/smiling-face-with-smiling-eyes"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 border-t border-white/10 pt-6">
|
||||
<h4 class="font-semibold">GET <code>/categories</code></h4>
|
||||
<div class="codewrap mt-3">
|
||||
<button class="copy-btn" data-copy-target="ex-curl-cats">Copy</button>
|
||||
<pre class="text-xs overflow-x-auto bg-black/30 rounded-lg p-3"><code id="ex-curl-cats">curl "<BASE_URL>/categories"</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="try-it" class="glass-card rounded-2xl p-6 scroll-mt-28">
|
||||
<h3 class="text-lg font-semibold">Try it</h3>
|
||||
<p class="text-sm text-gray-300 mt-2">Demo request is limited to <strong>page=1</strong> and <strong>limit=10</strong>.</p>
|
||||
<p id="ti-pro-note" class="hidden text-xs text-emerald-300 mt-2">Using Pro key via Authorization header.</p>
|
||||
<div class="grid gap-3 md:grid-cols-3 mt-4">
|
||||
<input id="ti-q" class="bg-[#151518] border border-white/10 rounded-xl px-3 py-2 text-sm text-gray-200" placeholder="keyword (love)">
|
||||
<input id="ti-category" class="bg-[#151518] border border-white/10 rounded-xl px-3 py-2 text-sm text-gray-200" placeholder="category (Smileys & Emotion)">
|
||||
<input id="ti-subcategory" class="bg-[#151518] border border-white/10 rounded-xl px-3 py-2 text-sm text-gray-200" placeholder="subcategory (face-smiling)">
|
||||
</div>
|
||||
<div class="mt-4 flex gap-3">
|
||||
<button id="ti-run" type="button" class="px-4 py-2 rounded-lg bg-brand-ocean hover:bg-brand-oceanSoft text-white text-sm">Run /emojis</button>
|
||||
<button id="ti-cats" type="button" class="px-4 py-2 rounded-lg bg-white/5 hover:bg-white/10 text-sm">Run /categories</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="errors" class="glass-card rounded-2xl p-6 scroll-mt-28">
|
||||
<h3 class="text-lg font-semibold">Errors & caching</h3>
|
||||
<ul class="list-disc pl-5 text-sm text-gray-300 space-y-1">
|
||||
<li><code>400</code> — invalid_request</li>
|
||||
<li><code>401</code> — invalid_key</li>
|
||||
<li><code>404</code> — not_found</li>
|
||||
<li><code>429</code> — rate_limited</li>
|
||||
</ul>
|
||||
<p class="text-sm text-gray-300 mt-2">Responses may include <code>ETag</code> and <code>Cache-Control: public, max-age=300</code>.</p>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
@push('scripts')
|
||||
<script>
|
||||
(() => {
|
||||
const BASE_API = @json(url('/v1'));
|
||||
const urlParams = new URLSearchParams(location.search);
|
||||
const proKey = urlParams.get('key') || '';
|
||||
const proBadge = document.getElementById('pro-badge');
|
||||
const proNote = document.getElementById('ti-pro-note');
|
||||
if (proKey) {
|
||||
proBadge?.classList.remove('hidden');
|
||||
proNote?.classList.remove('hidden');
|
||||
}
|
||||
|
||||
const baseUrlCode = document.getElementById('base-url-code');
|
||||
if (baseUrlCode) baseUrlCode.textContent = BASE_API;
|
||||
|
||||
const updateExamples = () => {
|
||||
const q = 'love';
|
||||
const cat = 'Smileys%20%26%20Emotion';
|
||||
const lim = 10;
|
||||
const exCurlEmojis = document.getElementById('ex-curl-emojis');
|
||||
if (exCurlEmojis) {
|
||||
exCurlEmojis.textContent = proKey
|
||||
? `curl -H "Authorization: Bearer ${proKey}" "${BASE_API}/emojis?q=${q}&category=${cat}&limit=${lim}&page=1"`
|
||||
: `curl "${BASE_API}/emojis?q=${q}&category=${cat}&limit=${lim}&page=1"`;
|
||||
}
|
||||
const exCurlCats = document.getElementById('ex-curl-cats');
|
||||
if (exCurlCats) {
|
||||
exCurlCats.textContent = proKey
|
||||
? `curl -H "Authorization: Bearer ${proKey}" "${BASE_API}/categories"`
|
||||
: `curl "${BASE_API}/categories"`;
|
||||
}
|
||||
const exCurlEmoji = document.getElementById('ex-curl-emoji');
|
||||
if (exCurlEmoji) {
|
||||
exCurlEmoji.textContent = `curl "${BASE_API}/emoji/smiling-face-with-smiling-eyes"`;
|
||||
}
|
||||
};
|
||||
updateExamples();
|
||||
|
||||
function textOf(id) {
|
||||
const el = document.getElementById(id);
|
||||
return el ? (el.textContent || el.innerText || '') : '';
|
||||
}
|
||||
document.querySelectorAll('.copy-btn').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const target = btn.getAttribute('data-copy-target');
|
||||
if (!target) return;
|
||||
try {
|
||||
await navigator.clipboard.writeText(textOf(target));
|
||||
const orig = btn.textContent;
|
||||
btn.textContent = '✅';
|
||||
setTimeout(() => { btn.textContent = orig || 'Copy'; }, 1200);
|
||||
} catch {}
|
||||
});
|
||||
});
|
||||
|
||||
const resultDrawer = document.createElement('aside');
|
||||
const backdrop = document.createElement('div');
|
||||
resultDrawer.id = 'ti-drawer';
|
||||
resultDrawer.className = 'fixed top-0 right-0 h-full w-full max-w-xl bg-[#0b0b0f] border-l border-white/10 translate-x-full transition-transform z-50';
|
||||
backdrop.className = 'fixed inset-0 bg-black/40 opacity-0 pointer-events-none transition-opacity z-40';
|
||||
resultDrawer.innerHTML = `
|
||||
<div class="flex items-center justify-between p-4 border-b border-white/10">
|
||||
<h3 class="text-lg font-semibold">Try it — Result</h3>
|
||||
<button id="ti-close" class="p-2 rounded-full text-gray-400 hover:bg-white/5">✕</button>
|
||||
</div>
|
||||
<div class="p-4 h-[calc(100%-64px)] overflow-auto">
|
||||
<pre class="p-3 rounded bg-black/30 overflow-auto text-xs"><code id="ti-result">{ }</code></pre>
|
||||
</div>`;
|
||||
document.body.appendChild(backdrop);
|
||||
document.body.appendChild(resultDrawer);
|
||||
|
||||
const openDrawer = () => {
|
||||
resultDrawer.classList.remove('translate-x-full');
|
||||
backdrop.classList.remove('opacity-0', 'pointer-events-none');
|
||||
backdrop.classList.add('opacity-100');
|
||||
document.body.style.overflow = 'hidden';
|
||||
};
|
||||
const closeDrawer = () => {
|
||||
resultDrawer.classList.add('translate-x-full');
|
||||
backdrop.classList.add('opacity-0', 'pointer-events-none');
|
||||
backdrop.classList.remove('opacity-100');
|
||||
document.body.style.overflow = '';
|
||||
};
|
||||
backdrop.addEventListener('click', closeDrawer);
|
||||
document.addEventListener('click', (e) => {
|
||||
const target = e.target;
|
||||
if (target && target.id === 'ti-close') closeDrawer();
|
||||
});
|
||||
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeDrawer(); });
|
||||
|
||||
const setResult = (obj) => {
|
||||
const el = document.getElementById('ti-result');
|
||||
if (!el) return;
|
||||
el.textContent = typeof obj === 'string' ? obj : JSON.stringify(obj, null, 2);
|
||||
};
|
||||
|
||||
document.getElementById('ti-run')?.addEventListener('click', async () => {
|
||||
const params = new URLSearchParams();
|
||||
const q = (document.getElementById('ti-q')?.value || '').trim();
|
||||
const c = (document.getElementById('ti-category')?.value || '').trim();
|
||||
const sc = (document.getElementById('ti-subcategory')?.value || '').trim();
|
||||
if (q) params.set('q', q);
|
||||
if (c) params.set('category', c);
|
||||
if (sc) params.set('subcategory', sc);
|
||||
params.set('limit', '10');
|
||||
params.set('page', '1');
|
||||
|
||||
const headers = {};
|
||||
if (proKey) headers['Authorization'] = 'Bearer ' + proKey;
|
||||
try {
|
||||
const res = await fetch(`${BASE_API}/emojis?` + params.toString(), { headers });
|
||||
if (!res.ok) throw new Error('Request failed: ' + res.status);
|
||||
const data = await res.json();
|
||||
setResult(data);
|
||||
} catch (e) {
|
||||
setResult(String(e));
|
||||
} finally {
|
||||
openDrawer();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('ti-cats')?.addEventListener('click', async () => {
|
||||
const headers = {};
|
||||
if (proKey) headers['Authorization'] = 'Bearer ' + proKey;
|
||||
try {
|
||||
const res = await fetch(`${BASE_API}/categories`, { headers });
|
||||
if (!res.ok) throw new Error('Request failed: ' + res.status);
|
||||
const data = await res.json();
|
||||
setResult(data);
|
||||
} catch (e) {
|
||||
setResult(String(e));
|
||||
} finally {
|
||||
openDrawer();
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user