📱 Mobile & Desktop Optimization: - Responsive grid layout: 1 card (mobile) → 2 cards (tablet) → 3 cards (desktop) → 4 cards (large screens) - Better card design with improved spacing and hover effects - Enhanced mobile experience with optimized touch targets 🔧 UI/UX Improvements: - Modern card-based layout instead of stacked list - Website logos with fallback icons for better visual recognition - Improved button placement and iconography - Better responsive breakpoints for different screen sizes ✨ Visual Enhancements: - Smooth hover animations and shadow effects - Better logo positioning with placeholder icons - Optimized spacing and typography for mobile devices - Professional card design with rounded corners and subtle shadows This update provides a much cleaner and more organized view of links, especially on mobile devices where the cards stack properly and buttons are easily accessible.
714 lines
25 KiB
HTML
Executable File
714 lines
25 KiB
HTML
Executable File
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Edit {{ page.title }}</title>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh;
|
|
padding: 20px;
|
|
}
|
|
|
|
.container {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
background: white;
|
|
border-radius: 15px;
|
|
box-shadow: 0 20px 40px 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 {
|
|
font-size: 2.2em;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.header p {
|
|
font-size: 1em;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.main-content {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 30px;
|
|
padding: 30px;
|
|
}
|
|
|
|
.form-section {
|
|
background: #f8f9fa;
|
|
padding: 25px;
|
|
border-radius: 10px;
|
|
border: 1px solid #e9ecef;
|
|
}
|
|
|
|
.form-section h2 {
|
|
color: #333;
|
|
margin-bottom: 20px;
|
|
font-size: 1.5em;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: 600;
|
|
color: #555;
|
|
}
|
|
|
|
.form-group input,
|
|
.form-group textarea {
|
|
width: 100%;
|
|
padding: 12px;
|
|
border: 2px solid #e9ecef;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
transition: border-color 0.3s;
|
|
}
|
|
|
|
.form-group input:focus,
|
|
.form-group textarea:focus {
|
|
outline: none;
|
|
border-color: #667eea;
|
|
}
|
|
|
|
.form-group textarea {
|
|
height: 80px;
|
|
resize: vertical;
|
|
}
|
|
|
|
.btn {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 12px 25px;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
cursor: pointer;
|
|
transition: transform 0.2s;
|
|
margin-right: 10px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.btn:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.btn:disabled {
|
|
opacity: 0.6;
|
|
cursor: not-allowed;
|
|
transform: none;
|
|
}
|
|
|
|
.btn-success {
|
|
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
|
|
}
|
|
|
|
.btn-danger {
|
|
background: linear-gradient(135deg, #dc3545 0%, #fd7e14 100%);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: linear-gradient(135deg, #6c757d 0%, #adb5bd 100%);
|
|
}
|
|
|
|
.links-section h2 {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.links-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
gap: 15px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.link-item {
|
|
background: white;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
margin-bottom: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 15px;
|
|
transition: all 0.3s ease;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
|
}
|
|
|
|
.link-item:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
|
border-color: #667eea;
|
|
}
|
|
|
|
.link-item.editing {
|
|
border-color: #667eea;
|
|
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2);
|
|
}
|
|
|
|
.link-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 12px;
|
|
}
|
|
|
|
.link-content {
|
|
flex: 1;
|
|
}
|
|
|
|
.link-logo {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 8px;
|
|
flex-shrink: 0;
|
|
object-fit: cover;
|
|
background: #f8f9fa;
|
|
border: 1px solid #e9ecef;
|
|
}
|
|
|
|
.link-icon-placeholder {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 8px;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: white;
|
|
font-size: 18px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.link-display {
|
|
display: block;
|
|
}
|
|
|
|
.link-edit {
|
|
display: none;
|
|
}
|
|
|
|
.link-item.editing .link-display {
|
|
display: none;
|
|
}
|
|
|
|
.link-item.editing .link-edit {
|
|
display: block;
|
|
}
|
|
|
|
.link-title {
|
|
font-size: 1.2em;
|
|
font-weight: 600;
|
|
color: #333;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.link-description {
|
|
color: #666;
|
|
font-size: 0.9em;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.link-url {
|
|
color: #667eea;
|
|
font-size: 0.9em;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.link-actions {
|
|
margin-top: 15px;
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.btn-small {
|
|
padding: 8px 15px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 40px 20px;
|
|
color: #666;
|
|
background: white;
|
|
border-radius: 8px;
|
|
border: 1px solid #e9ecef;
|
|
}
|
|
|
|
.empty-state .icon {
|
|
font-size: 3em;
|
|
margin-bottom: 15px;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.page-actions {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
text-align: center;
|
|
border-top: 1px solid #e9ecef;
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 15px;
|
|
}
|
|
|
|
.alert {
|
|
padding: 12px 20px;
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
display: none;
|
|
}
|
|
|
|
.alert-success {
|
|
background: #d4edda;
|
|
border: 1px solid #c3e6cb;
|
|
color: #155724;
|
|
}
|
|
|
|
.alert-error {
|
|
background: #f8d7da;
|
|
border: 1px solid #f5c6cb;
|
|
color: #721c24;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
body {
|
|
padding: 10px;
|
|
}
|
|
|
|
.container {
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.header {
|
|
padding: 20px 15px;
|
|
}
|
|
|
|
.header h1 {
|
|
font-size: 1.8em;
|
|
}
|
|
|
|
.main-content {
|
|
grid-template-columns: 1fr;
|
|
gap: 20px;
|
|
padding: 20px 15px;
|
|
}
|
|
|
|
.form-section {
|
|
padding: 20px 15px;
|
|
}
|
|
|
|
.links-grid {
|
|
grid-template-columns: 1fr;
|
|
gap: 12px;
|
|
}
|
|
|
|
.link-item {
|
|
padding: 15px;
|
|
}
|
|
|
|
.link-header {
|
|
gap: 10px;
|
|
}
|
|
|
|
.link-logo,
|
|
.link-icon-placeholder {
|
|
width: 35px;
|
|
height: 35px;
|
|
}
|
|
|
|
.link-title {
|
|
font-size: 1.1em;
|
|
}
|
|
|
|
.link-actions {
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.link-actions .btn-small {
|
|
width: 100%;
|
|
text-align: center;
|
|
}
|
|
|
|
.page-actions {
|
|
flex-direction: column;
|
|
padding: 15px;
|
|
gap: 10px;
|
|
}
|
|
|
|
.page-actions .btn {
|
|
width: 100%;
|
|
text-align: center;
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 769px) and (max-width: 1024px) {
|
|
.links-grid {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1025px) {
|
|
.links-grid {
|
|
grid-template-columns: repeat(3, 1fr);
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1400px) {
|
|
.links-grid {
|
|
grid-template-columns: repeat(4, 1fr);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>✏️ Edit Links</h1>
|
|
<p>Manage your link collection: {{ page.title }}</p>
|
|
{% if page.short_url %}
|
|
<div style="margin-top: 15px; padding: 12px; background: rgba(255,255,255,0.2); border-radius: 8px; font-size: 0.9em;">
|
|
<strong>🔗 Page Short URL:</strong>
|
|
<a href="{{ page.short_url }}" target="_blank" style="color: #fff; text-decoration: underline;">{{ page.short_url }}</a>
|
|
<button onclick="copyToClipboard('{{ page.short_url }}')" style="margin-left: 10px; padding: 4px 8px; background: rgba(255,255,255,0.3); color: white; border: 1px solid rgba(255,255,255,0.5); border-radius: 3px; cursor: pointer; font-size: 0.8em;">Copy</button>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="alert alert-success" id="success-alert">
|
|
Operation completed successfully!
|
|
</div>
|
|
|
|
<div class="alert alert-error" id="error-alert">
|
|
An error occurred. Please try again.
|
|
</div>
|
|
|
|
<div class="main-content">
|
|
<div class="form-section">
|
|
<h2>Add New Link</h2>
|
|
<form id="add-link-form">
|
|
<div class="form-group">
|
|
<label for="link-title">Title *</label>
|
|
<input type="text" id="link-title" placeholder="Link title" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="link-url">URL *</label>
|
|
<input type="url" id="link-url" placeholder="https://example.com" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="link-description">Description</label>
|
|
<textarea id="link-description" placeholder="Optional description"></textarea>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-success">Add Link</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="links-section">
|
|
<h2>Current Links ({{ page.links|length }})</h2>
|
|
<div class="links-grid" id="links-container">
|
|
{% if page.links %}
|
|
{% for link in page.links %}
|
|
<div class="link-item" data-link-id="{{ link.id }}">
|
|
<div class="link-display">
|
|
<div class="link-header">
|
|
<div class="link-icon-placeholder" style="display: flex;">🔗</div>
|
|
<img class="link-logo" src="" alt="" style="display: none;" onerror="this.style.display='none'">
|
|
<div class="link-content">
|
|
<div class="link-title">{{ link.title }}</div>
|
|
{% if link.description %}
|
|
<div class="link-description">{{ link.description }}</div>
|
|
{% endif %}
|
|
<div class="link-url" data-url="{{ link.url }}">{{ link.url }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if link.short_url %}
|
|
<div class="short-url-display" style="margin-top: 12px; padding: 10px; background: #e3f2fd; border-radius: 8px; border-left: 3px solid #2196f3;">
|
|
<small style="color: #1976d2; font-weight: 600;">🔗 Short URL:</small>
|
|
<br>
|
|
<a href="{{ link.short_url }}" target="_blank" style="color: #1976d2; text-decoration: none; font-family: monospace; font-size: 0.9em;">{{ link.short_url }}</a>
|
|
<button class="btn-copy" onclick="copyToClipboard('{{ link.short_url }}')" style="margin-left: 8px; padding: 3px 8px; background: #2196f3; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 0.8em;">Copy</button>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="link-actions">
|
|
<button class="btn btn-small btn-secondary" onclick="editLink('{{ link.id }}')">✏️ Edit</button>
|
|
<button class="btn btn-small btn-danger" onclick="deleteLink('{{ link.id }}')">🗑️ Delete</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="link-edit">
|
|
<div class="form-group">
|
|
<label>Title</label>
|
|
<input type="text" class="edit-title" value="{{ link.title }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>URL</label>
|
|
<input type="url" class="edit-url" value="{{ link.url }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Description</label>
|
|
<textarea class="edit-description">{{ link.description or '' }}</textarea>
|
|
</div>
|
|
<div class="link-actions">
|
|
<button class="btn btn-small btn-success" onclick="saveLink('{{ link.id }}')">💾 Save</button>
|
|
<button class="btn btn-small btn-secondary" onclick="cancelEdit('{{ link.id }}')">❌ Cancel</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<div class="empty-state" style="grid-column: 1 / -1;">
|
|
<div class="icon">📝</div>
|
|
<h3>No links yet</h3>
|
|
<p>Add your first link using the form on the left.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="page-actions">
|
|
<a href="/stats/{{ page.id }}" class="btn">📊 View Statistics</a>
|
|
<a href="/links/{{ page.id }}" target="_blank" class="btn btn-secondary">👁️ Preview Public Page</a>
|
|
<a href="/" class="btn btn-secondary">🏠 Back to Dashboard</a>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const pageId = '{{ page.id }}';
|
|
|
|
// Social media and website logo detection
|
|
function getWebsiteLogo(url) {
|
|
try {
|
|
const urlObj = new URL(url.startsWith('http') ? url : 'https://' + url);
|
|
const domain = urlObj.hostname.toLowerCase().replace('www.', '');
|
|
|
|
// Logo mapping for popular sites
|
|
const logoMap = {
|
|
'facebook.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/facebook.svg',
|
|
'instagram.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/instagram.svg',
|
|
'twitter.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/twitter.svg',
|
|
'x.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/x.svg',
|
|
'tiktok.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/tiktok.svg',
|
|
'youtube.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/youtube.svg',
|
|
'linkedin.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/linkedin.svg',
|
|
'pinterest.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/pinterest.svg',
|
|
'snapchat.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/snapchat.svg',
|
|
'whatsapp.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/whatsapp.svg',
|
|
'telegram.org': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/telegram.svg',
|
|
'discord.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/discord.svg',
|
|
'reddit.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/reddit.svg',
|
|
'github.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/github.svg',
|
|
'gmail.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/gmail.svg',
|
|
'google.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/google.svg',
|
|
'amazon.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/amazon.svg',
|
|
'apple.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/apple.svg',
|
|
'microsoft.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/microsoft.svg',
|
|
'spotify.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/spotify.svg',
|
|
'netflix.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/netflix.svg',
|
|
'twitch.tv': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/twitch.svg',
|
|
'dropbox.com': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/dropbox.svg',
|
|
'zoom.us': 'https://cdn.jsdelivr.net/npm/simple-icons@v9/icons/zoom.svg'
|
|
};
|
|
|
|
if (logoMap[domain]) {
|
|
return logoMap[domain];
|
|
}
|
|
|
|
// Fallback to favicon
|
|
return `https://www.google.com/s2/favicons?domain=${domain}&sz=64`;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Set logos for existing links
|
|
function setLogosForLinks() {
|
|
document.querySelectorAll('.link-url[data-url]').forEach(linkElement => {
|
|
const url = linkElement.getAttribute('data-url');
|
|
const linkItem = linkElement.closest('.link-item');
|
|
const logoImg = linkItem.querySelector('.link-logo');
|
|
const placeholder = linkItem.querySelector('.link-icon-placeholder');
|
|
const logoSrc = getWebsiteLogo(url);
|
|
|
|
if (logoSrc && logoImg) {
|
|
logoImg.src = logoSrc;
|
|
logoImg.alt = new URL(url.startsWith('http') ? url : 'https://' + url).hostname;
|
|
|
|
// Show logo and hide placeholder when loaded
|
|
logoImg.onload = function() {
|
|
logoImg.style.display = 'block';
|
|
if (placeholder) placeholder.style.display = 'none';
|
|
};
|
|
|
|
// Show placeholder if logo fails to load
|
|
logoImg.onerror = function() {
|
|
logoImg.style.display = 'none';
|
|
if (placeholder) placeholder.style.display = 'flex';
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize logos when page loads
|
|
document.addEventListener('DOMContentLoaded', setLogosForLinks);
|
|
|
|
// Copy to clipboard function
|
|
function copyToClipboard(text) {
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
// Show temporary success message
|
|
const btn = event.target;
|
|
const originalText = btn.textContent;
|
|
btn.textContent = 'Copied!';
|
|
btn.style.background = '#4caf50';
|
|
setTimeout(() => {
|
|
btn.textContent = originalText;
|
|
btn.style.background = '#2196f3';
|
|
}, 1500);
|
|
}).catch(function(err) {
|
|
console.error('Could not copy text: ', err);
|
|
alert('Failed to copy to clipboard');
|
|
});
|
|
}
|
|
|
|
// Add new link
|
|
document.getElementById('add-link-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const title = document.getElementById('link-title').value;
|
|
const url = document.getElementById('link-url').value;
|
|
const description = document.getElementById('link-description').value;
|
|
|
|
try {
|
|
const response = await fetch(`/api/link_pages/${pageId}/links`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
title,
|
|
url,
|
|
description
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
showAlert('Link added successfully!', 'success');
|
|
setTimeout(() => location.reload(), 1000);
|
|
} else {
|
|
showAlert(result.error || 'Failed to add link', 'error');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Network error occurred', 'error');
|
|
}
|
|
});
|
|
|
|
// Edit link
|
|
function editLink(linkId) {
|
|
const linkItem = document.querySelector(`[data-link-id="${linkId}"]`);
|
|
linkItem.classList.add('editing');
|
|
}
|
|
|
|
// Cancel edit
|
|
function cancelEdit(linkId) {
|
|
const linkItem = document.querySelector(`[data-link-id="${linkId}"]`);
|
|
linkItem.classList.remove('editing');
|
|
}
|
|
|
|
// Save link
|
|
async function saveLink(linkId) {
|
|
const linkItem = document.querySelector(`[data-link-id="${linkId}"]`);
|
|
const title = linkItem.querySelector('.edit-title').value;
|
|
const url = linkItem.querySelector('.edit-url').value;
|
|
const description = linkItem.querySelector('.edit-description').value;
|
|
|
|
try {
|
|
const response = await fetch(`/api/link_pages/${pageId}/links/${linkId}`, {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
title,
|
|
url,
|
|
description
|
|
})
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
showAlert('Link updated successfully!', 'success');
|
|
setTimeout(() => location.reload(), 1000);
|
|
} else {
|
|
showAlert(result.error || 'Failed to update link', 'error');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Network error occurred', 'error');
|
|
}
|
|
}
|
|
|
|
// Delete link
|
|
async function deleteLink(linkId) {
|
|
if (!confirm('Are you sure you want to delete this link?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/link_pages/${pageId}/links/${linkId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
showAlert('Link deleted successfully!', 'success');
|
|
setTimeout(() => location.reload(), 1000);
|
|
} else {
|
|
showAlert(result.error || 'Failed to delete link', 'error');
|
|
}
|
|
} catch (error) {
|
|
showAlert('Network error occurred', 'error');
|
|
}
|
|
}
|
|
|
|
// Show alert
|
|
function showAlert(message, type) {
|
|
const alert = document.getElementById(`${type}-alert`);
|
|
alert.textContent = message;
|
|
alert.style.display = 'block';
|
|
|
|
setTimeout(() => {
|
|
alert.style.display = 'none';
|
|
}, 3000);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|