Spaces:
Runtime error
Runtime error
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>CMS - Trung Tâm Nha Khoa Nhẹ Nhàng</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| body { | |
| background-color: #f3f4f6; | |
| color: #111827; | |
| } | |
| .sidebar { | |
| transition: all 0.3s ease; | |
| } | |
| .sidebar.collapsed { | |
| width: 80px; | |
| } | |
| .sidebar.collapsed .sidebar-text, .sidebar.collapsed .logo-text { | |
| display: none; | |
| } | |
| .sidebar-link { | |
| position: relative; | |
| } | |
| .sidebar-link.active::before { | |
| content: ''; | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| height: 100%; | |
| width: 4px; | |
| background-color: #3b82f6; | |
| } | |
| .content-area { | |
| transition: all 0.3s ease; | |
| } | |
| .content-area.expanded { | |
| margin-left: 80px; | |
| } | |
| .image-preview { | |
| max-height: 200px; | |
| object-fit: contain; | |
| } | |
| .editor-toolbar { | |
| border: 1px solid #e5e7eb; | |
| border-bottom: none; | |
| border-radius: 4px 4px 0 0; | |
| } | |
| .editor-content { | |
| border: 1px solid #e5e7eb; | |
| border-radius: 0 0 4px 4px; | |
| min-height: 300px; | |
| padding: 10px; | |
| } | |
| .case-card { | |
| position: relative; | |
| overflow: hidden; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 6px rgba(0,0,0,0.1); | |
| transition: all 0.3s ease; | |
| } | |
| .case-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 10px 15px rgba(0,0,0,0.1); | |
| } | |
| </style> | |
| </head> | |
| <body class="font-sans"> | |
| <div class="flex h-screen overflow-hidden"> | |
| <!-- Sidebar --> | |
| <div class="sidebar bg-gray-800 text-white h-full fixed z-50 w-64"> | |
| <div class="flex items-center justify-between p-4 border-b border-gray-700"> | |
| <div class="flex items-center"> | |
| <i class="fas fa-tooth text-2xl text-blue-400 mr-3"></i> | |
| <span class="logo-text text-xl font-bold">TTL1979 CMS</span> | |
| </div> | |
| <button id="toggle-sidebar" class="text-gray-400 hover:text-white"> | |
| <i class="fas fa-bars"></i> | |
| </button> | |
| </div> | |
| <div class="p-4"> | |
| <div class="mb-8"> | |
| <div class="text-gray-400 uppercase text-xs font-semibold mb-2 sidebar-text">Main Menu</div> | |
| <ul> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700 {% if section == 'dashboard-section' %}active{% endif %}" data-section="dashboard-section"> | |
| <i class="fas fa-tachometer-alt mr-3 text-blue-400"></i> | |
| <span class="sidebar-text">Dashboard</span> | |
| </a> | |
| </li> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700 {% if section == 'pages-section' %}active{% endif %}" data-section="pages-section"> | |
| <i class="fas fa-file-alt mr-3 text-green-400"></i> | |
| <span class="sidebar-text">Pages</span> | |
| </a> | |
| </li> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700 {% if section == 'posts-section' %}active{% endif %}" data-section="posts-section"> | |
| <i class="fas fa-newspaper mr-3 text-purple-400"></i> | |
| <span class="sidebar-text">Posts</span> | |
| </a> | |
| </li> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700 {% if section == 'cases-section' %}active{% endif %}" data-section="cases-section"> | |
| <i class="fas fa-images mr-3 text-yellow-400"></i> | |
| <span class="sidebar-text">Case Studies</span> | |
| </a> | |
| </li> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700 {% if section == 'media-section' %}active{% endif %}" data-section="media-section"> | |
| <i class="fas fa-photo-video mr-3 text-red-400"></i> | |
| <span class="sidebar-text">Media Library</span> | |
| </a> | |
| </li> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700 {% if section == 'settings-section' %}active{% endif %}" data-section="settings-section"> | |
| <i class="fas fa-cog mr-3 text-gray-400"></i> | |
| <span class="sidebar-text">Settings</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| <div class="mb-8"> | |
| <div class="text-gray-400 uppercase text-xs font-semibold mb-2 sidebar-text">User</div> | |
| <ul> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700 {% if section == 'profile-section' %}active{% endif %}" data-section="profile-section"> | |
| <i class="fas fa-user mr-3 text-indigo-400"></i> | |
| <span class="sidebar-text">Profile</span> | |
| </a> | |
| </li> | |
| <li class="mb-1"> | |
| <a href="#" class="sidebar-link flex items-center p-2 rounded hover:bg-gray-700" id="logout-btn"> | |
| <i class="fas fa-sign-out-alt mr-3 text-pink-400"></i> | |
| <span class="sidebar-text">Logout</span> | |
| </a> | |
| </li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="content-area flex-1 overflow-auto ml-64"> | |
| <nav class="bg-white shadow-sm p-4 flex justify-between items-center"> | |
| <div> | |
| <h1 class="text-xl font-semibold text-gray-800" id="page-title"> | |
| {% if section == 'dashboard-section' %}Dashboard | |
| {% elif section == 'pages-section' %}Pages | |
| {% elif section == 'posts-section' %}Posts | |
| {% elif section == 'cases-section' %}Case Studies | |
| {% elif section == 'media-section' %}Media Library | |
| {% elif section == 'settings-section' %}Settings | |
| {% elif section == 'profile-section' %}Profile | |
| {% elif section == 'page-editor-section' %}{% if page %}Edit Page{% else %}New Page{% endif %} | |
| {% elif section == 'post-editor-section' %}{% if post %}Edit Post{% else %}New Post{% endif %} | |
| {% elif section == 'case-editor-section' %}{% if case %}Edit Case Study{% else %}New Case Study{% endif %} | |
| {% else %}Dashboard{% endif %} | |
| </h1> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <div class="relative"> | |
| <button id="notifications-btn" class="text-gray-500 hover:text-gray-700 relative"> | |
| <i class="fas fa-bell text-xl"></i> | |
| <span class="absolute top-0 right-0 h-2 w-2 rounded-full bg-red-500"></span> | |
| </button> | |
| <div id="notifications-dropdown" class="hidden absolute right-0 mt-2 w-64 bg-white rounded-md shadow-lg py-1 z-50"> | |
| <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">New case study added</a> | |
| <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">New appointment request</a> | |
| <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">System update available</a> | |
| </div> | |
| </div> | |
| <div class="flex items-center"> | |
| <img src="https://randomuser.me/api/portraits/men/32.jpg" alt="User" class="w-8 h-8 rounded-full mr-2"> | |
| <span class="text-gray-700">Admin</span> | |
| </div> | |
| </div> | |
| </nav> | |
| <div class="p-6"> | |
| <!-- Dashboard Section --> | |
| <div id="dashboard-section" class="section-content" {% if section != 'dashboard-section' %}style="display: none;"{% endif %}> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8"> | |
| <div class="bg-white rounded-lg shadow p-6"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4"> | |
| <i class="fas fa-file-alt text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500">Pages</p> | |
| <h3 class="text-2xl font-bold">{{ pages | length }}</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow p-6"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-green-100 text-green-600 mr-4"> | |
| <i class="fas fa-newspaper text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500">Posts</p> | |
| <h3 class="text-2xl font-bold">{{ posts | length }}</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow p-6"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-yellow-100 text-yellow-600 mr-4"> | |
| <i class="fas fa-images text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500">Case Studies</p> | |
| <h3 class="text-2xl font-bold">{{ cases | length }}</h3> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow p-6"> | |
| <div class="flex items-center"> | |
| <div class="p-3 rounded-full bg-purple-100 text-purple-600 mr-4"> | |
| <i class="fas fa-image text-xl"></i> | |
| </div> | |
| <div> | |
| <p class="text-gray-500">Media Files</p> | |
| <h3 class="text-2xl font-bold">0</h3> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8"> | |
| <div class="bg-white rounded-lg shadow p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-lg font-semibold">Recent Pages</h3> | |
| <a href="#" class="text-blue-500 text-sm" data-section="pages-section">View All</a> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead> | |
| <tr> | |
| <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Title</th> | |
| <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> | |
| <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Modified</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| {% if pages %} | |
| {% for page in pages[:3] %} | |
| <tr> | |
| <td class="px-4 py-3 whitespace-nowrap">{{ page.title }}</td> | |
| <td class="px-4 py-3 whitespace-nowrap">{{ page.status }}</td> | |
| <td class="px-4 py-3 whitespace-nowrap">{{ page.last_modified }}</td> | |
| </tr> | |
| {% endfor %} | |
| {% else %} | |
| <tr> | |
| <td colspan="3" class="px-4 py-3 text-center text-gray-500">No pages available</td> | |
| </tr> | |
| {% endif %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-lg font-semibold">Recent Case Studies</h3> | |
| <a href="#" class="text-blue-500 text-sm" data-section="cases-section">View All</a> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead> | |
| <tr> | |
| <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Title</th> | |
| <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Treatment</th> | |
| <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| {% if cases %} | |
| {% for case in cases[:3] %} | |
| <tr> | |
| <td class="px-4 py-3 whitespace-nowrap">{{ case.title }}</td> | |
| <td class="px-4 py-3 whitespace-nowrap">{{ case.treatment }}</td> | |
| <td class="px-4 py-3 whitespace-nowrap">{{ case.date }}</td> | |
| </tr> | |
| {% endfor %} | |
| {% else %} | |
| <tr> | |
| <td colspan="3" class="px-4 py-3 text-center text-gray-500">No case studies available</td> | |
| </tr> | |
| {% endif %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow p-6"> | |
| <div class="flex justify-between items-center mb-4"> | |
| <h3 class="text-lg font-semibold">Quick Actions</h3> | |
| </div> | |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-4"> | |
| <a href="{{ url_for('add_page') }}" class="quick-action-btn"> | |
| <div class="p-4 border border-gray-200 rounded-lg text-center hover:bg-gray-50 transition"> | |
| <i class="fas fa-file-alt text-2xl text-blue-500 mb-2"></i> | |
| <p>New Page</p> | |
| </div> | |
| </a> | |
| <a href="{{ url_for('add_post') }}" class="quick-action-btn"> | |
| <div class="p-4 border border-gray-200 rounded-lg text-center hover:bg-gray-50 transition"> | |
| <i class="fas fa-newspaper text-2xl text-green-500 mb-2"></i> | |
| <p>New Post</p> | |
| </div> | |
| </a> | |
| <a href="{{ url_for('add_case') }}" class="quick-action-btn"> | |
| <div class="p-4 border border-gray-200 rounded-lg text-center hover:bg-gray-50 transition"> | |
| <i class="fas fa-images text-2xl text-yellow-500 mb-2"></i> | |
| <p>New Case</p> | |
| </div> | |
| </a> | |
| <a href="#" class="quick-action-btn" data-section="media-section"> | |
| <div class="p-4 border border-gray-200 rounded-lg text-center hover:bg-gray-50 transition"> | |
| <i class="fas fa-upload text-2xl text-purple-500 mb-2"></i> | |
| <p>Upload Media</p> | |
| </div> | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Pages Section --> | |
| <div id="pages-section" class="section-content" {% if section != 'pages-section' %}style="display: none;"{% endif %}> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">Pages</h2> | |
| <a href="{{ url_for('add_page') }}" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-plus mr-2"></i> New Page | |
| </a> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="flex flex-col md:flex-row md:items-center md:justify-between"> | |
| <div class="relative mb-4 md:mb-0 md:w-64"> | |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <i class="fas fa-search text-gray-400"></i> | |
| </div> | |
| <input type="text" id="pages-search" class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" placeholder="Search pages..."> | |
| </div> | |
| <div class="flex items-center space-x-2"> | |
| <select id="pages-filter" class="block w-full md:w-auto pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="all">All Pages</option> | |
| <option value="published">Published</option> | |
| <option value="draft">Draft</option> | |
| <option value="private">Private</option> | |
| </select> | |
| <button id="pages-bulk-actions" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| Bulk Actions | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | |
| <input type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| </th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Title</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Author</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Modified</th> | |
| <th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| {% if pages %} | |
| {% for page in pages %} | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <input type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ page.title }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">Admin</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ page.status }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ page.last_modified }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <a href="{{ url_for('edit_page', id=page.id) }}" class="text-blue-500 hover:text-blue-700">Edit</a> | |
| <a href="{{ url_for('delete_page', id=page.id) }}" class="text-red-500 hover:text-red-700 ml-4">Delete</a> | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| {% else %} | |
| <tr> | |
| <td colspan="6" class="px-6 py-4 text-center text-gray-500">No pages available</td> | |
| </tr> | |
| {% endif %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Page Editor Section --> | |
| <div id="page-editor-section" class="section-content" {% if section != 'page-editor-section' %}style="display: none;"{% endif %}> | |
| <form method="POST" action="{% if page %}{{ url_for('edit_page', id=page.id) }}{% else %}{{ url_for('add_page') }}{% endif %}"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">{% if page %}Edit Page{% else %}New Page{% endif %}</h2> | |
| <div class="flex space-x-2"> | |
| <button type="submit" name="preview" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-eye mr-2"></i> Preview | |
| </button> | |
| <button type="submit" name="save" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-save mr-2"></i> Save | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div class="md:col-span-2"> | |
| <label for="page-title" class="block text-sm font-medium text-gray-700 mb-1">Page Title</label> | |
| <input type="text" id="page-title" name="page-title" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if page %}{{ page.title }}{% endif %}" required> | |
| </div> | |
| <div> | |
| <label for="page-slug" class="block text-sm font-medium text-gray-700 mb-1">URL Slug</label> | |
| <div class="flex"> | |
| <span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm">/</span> | |
| <input type="text" id="page-slug" name="page-slug" class="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-md border border-gray-300 focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if page %}{{ page.slug }}{% endif %}" required> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div> | |
| <label for="page-status" class="block text-sm font-medium text-gray-700 mb-1">Status</label> | |
| <select id="page-status" name="page-status" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="draft" {% if page and page.status == 'draft' %}selected{% endif %}>Draft</option> | |
| <option value="published" {% if page and page.status == 'published' %}selected{% endif %}>Published</option> | |
| <option value="private" {% if page and page.status == 'private' %}selected{% endif %}>Private</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label for="page-template" class="block text-sm font-medium text-gray-700 mb-1">Template</label> | |
| <select id="page-template" name="page-template" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="default" {% if page and page.template == 'default' %}selected{% endif %}>Default Template</option> | |
| <option value="full-width" {% if page and page.template == 'full-width' %}selected{% endif %}>Full Width</option> | |
| <option value="homepage" {% if page and page.template == 'homepage' %}selected{% endif %}>Homepage</option> | |
| <option value="contact" {% if page and page.template == 'contact' %}selected{% endif %}>Contact Page</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label for="page-parent" class="block text-sm font-medium text-gray-700 mb-1">Parent Page</label> | |
| <select id="page-parent" name="page-parent" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="0" {% if page and page.parent_id == 0 %}selected{% endif %}>(no parent)</option> | |
| {% for p in pages %} | |
| <option value="{{ p.id }}" {% if page and page.parent_id == p.id %}selected{% endif %}>{{ p.title }}</option> | |
| {% endfor %} | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4"> | |
| <label for="page-content" class="block text-sm font-medium text-gray-700 mb-1">Content</label> | |
| <div class="editor-toolbar bg-gray-100 p-2"> | |
| <div class="flex flex-wrap items-center space-x-1"> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="bold"><i class="fas fa-bold"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="italic"><i class="fas fa-italic"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="underline"><i class="fas fa-underline"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertUnorderedList"><i class="fas fa-list-ul"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertOrderedList"><i class="fas fa-list-ol"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="createLink"><i class="fas fa-link"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="unlink"><i class="fas fa-unlink"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertImage"><i class="fas fa-image"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertVideo"><i class="fas fa-video"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="undo"><i class="fas fa-undo"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="redo"><i class="fas fa-redo"></i></button> | |
| </div> | |
| </div> | |
| <div id="page-content" class="editor-content focus:outline-none focus:ring-2 focus:ring-blue-500" contenteditable="true">{% if page %}{{ page.content | safe }}{% else %}<p>Start writing your page content here...</p>{% endif %}</div> | |
| <input type="hidden" id="page-content-hidden" name="page-content"> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
| <div class="md:col-span-2"> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">Featured Image</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div id="featured-image-container" class="border-2 border-dashed border-gray-300 rounded-md p-4 text-center"> | |
| <div id="featured-image-preview" class="{% if not page or not page.featured_image %}hidden{% endif %} mb-4"> | |
| <img src="{% if page %}{{ page.featured_image }}{% endif %}" alt="Featured Image" class="image-preview mx-auto"> | |
| </div> | |
| <div id="featured-image-upload"> | |
| <i class="fas fa-image text-4xl text-gray-400 mb-2"></i> | |
| <p class="text-sm text-gray-500 mb-2">Drag & drop an image here, or click to select</p> | |
| <button type="button" id="upload-featured-image-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md text-sm"> | |
| Select Image | |
| </button> | |
| <input type="text" id="featured-image" name="featured-image" class="hidden" value="{% if page %}{{ page.featured_image }}{% endif %}"> | |
| </div> | |
| </div> | |
| <div class="mt-2 flex justify-between"> | |
| <button type="button" id="remove-featured-image-btn" class="text-red-500 text-sm hover:text-red-700 {% if not page or not page.featured_image %}hidden{% endif %}">Remove Image</button> | |
| <button type="button" id="edit-featured-image-btn" class="text-blue-500 text-sm hover:text-blue-700 {% if not page or not page.featured_image %}hidden{% endif %}">Edit Image</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">SEO Settings</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div class="mb-4"> | |
| <label for="seo-title" class="block text-sm font-medium text-gray-700 mb-1">SEO Title</label> | |
| <input type="text" id="seo-title" name="seo-title" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if page %}{{ page.seo_title }}{% endif %}"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="seo-description" class="block text-sm font-medium text-gray-700 mb-1">Meta Description</label> | |
| <textarea id="seo-description" name="seo-description" rows="3" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">{% if page %}{{ page.seo_description }}{% endif %}</textarea> | |
| </div> | |
| <div> | |
| <label for="seo-keywords" class="block text-sm font-medium text-gray-700 mb-1">Keywords</label> | |
| <input type="text" id="seo-keywords" name="seo-keywords" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if page %}{{ page.seo_keywords }}{% endif %}"> | |
| <p class="mt-1 text-xs text-gray-500">Separate keywords with commas</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </form> | |
| </div> | |
| <!-- Posts Section --> | |
| <div id="posts-section" class="section-content" {% if section != 'posts-section' %}style="display: none;"{% endif %}> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">Posts</h2> | |
| <a href="{{ url_for('add_post') }}" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-plus mr-2"></i> New Post | |
| </a> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="flex flex-col md:flex-row md:items-center md:justify-between"> | |
| <div class="relative mb-4 md:mb-0 md:w-64"> | |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <i class="fas fa-search text-gray-400"></i> | |
| </div> | |
| <input type="text" id="posts-search" class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" placeholder="Search posts..."> | |
| </div> | |
| <div class="flex items-center space-x-2"> | |
| <select id="posts-filter" class="block w-full md:w-auto pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="all">All Posts</option> | |
| <option value="published">Published</option> | |
| <option value="draft">Draft</option> | |
| </select> | |
| <select id="posts-category-filter" class="block w-full md:w-auto pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="all">All Categories</option> | |
| <option value="dental-care">Dental Care</option> | |
| <option value="cosmetic">Cosmetic Dentistry</option> | |
| <option value="orthodontics">Orthodontics</option> | |
| <option value="implants">Implants</option> | |
| </select> | |
| <button id="posts-bulk-actions" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| Bulk Actions | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | |
| <input type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| </th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Title</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Categories</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Publish Date</th> | |
| <th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| {% if posts %} | |
| {% for post in posts %} | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <input type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ post.title }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ post.categories }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ post.status }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ post.publish_date }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <a href="{{ url_for('edit_post', id=post.id) }}" class="text-blue-500 hover:text-blue-700">Edit</a> | |
| <a href="{{ url_for('delete_post', id=post.id) }}" class="text-red-500 hover:text-red-700 ml-4">Delete</a> | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| {% else %} | |
| <tr> | |
| <td colspan="6" class="px-6 py-4 text-center text-gray-500">No posts available</td> | |
| </tr> | |
| {% endif %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Post Editor Section --> | |
| <div id="post-editor-section" class="section-content" {% if section != 'post-editor-section' %}style="display: none;"{% endif %}> | |
| <form method="POST" action="{% if post %}{{ url_for('edit_post', id=post.id) }}{% else %}{{ url_for('add_post') }}{% endif %}"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">{% if post %}Edit Post{% else %}New Post{% endif %}</h2> | |
| <div class="flex space-x-2"> | |
| <button type="submit" name="preview" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-eye mr-2"></i> Preview | |
| </button> | |
| <button type="submit" name="save" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-save mr-2"></i> Save | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div class="md:col-span-2"> | |
| <label for="post-title" class="block text-sm font-medium text-gray-700 mb-1">Post Title</label> | |
| <input type="text" id="post-title" name="post-title" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if post %}{{ post.title }}{% endif %}" required> | |
| </div> | |
| <div> | |
| <label for="post-slug" class="block text-sm font-medium text-gray-700 mb-1">URL Slug</label> | |
| <div class="flex"> | |
| <span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm">/blog/</span> | |
| <input type="text" id="post-slug" name="post-slug" class="flex-1 min-w-0 block w-full px-3 py-2 rounded-none rounded-r-md border border-gray-300 focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if post %}{{ post.slug }}{% endif %}" required> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div> | |
| <label for="post-status" class="block text-sm font-medium text-gray-700 mb-1">Status</label> | |
| <select id="post-status" name="post-status" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="draft" {% if post and post.status == 'draft' %}selected{% endif %}>Draft</option> | |
| <option value="published" {% if post and post.status == 'published' %}selected{% endif %}>Published</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label for="post-publish-date" class="block text-sm font-medium text-gray-700 mb-1">Publish Date</label> | |
| <input type="date" id="post-publish-date" name="post-publish-date" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if post %}{{ post.publish_date }}{% endif %}"> | |
| </div> | |
| <div> | |
| <label for="post-categories" class="block text-sm font-medium text-gray-700 mb-1">Categories</label> | |
| <select id="post-categories" name="post-categories" multiple class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="dental-care" {% if post and 'dental-care' in post.categories.split(',') %}selected{% endif %}>Dental Care</option> | |
| <option value="cosmetic" {% if post and 'cosmetic' in post.categories.split(',') %}selected{% endif %}>Cosmetic Dentistry</option> | |
| <option value="orthodontics" {% if post and 'orthodontics' in post.categories.split(',') %}selected{% endif %}>Orthodontics</option> | |
| <option value="implants" {% if post and 'implants' in post.categories.split(',') %}selected{% endif %}>Implants</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4"> | |
| <label for="post-excerpt" class="block text-sm font-medium text-gray-700 mb-1">Excerpt</label> | |
| <textarea id="post-excerpt" name="post-excerpt" rows="3" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm mb-4">{% if post %}{{ post.excerpt }}{% endif %}</textarea> | |
| <label for="post-content" class="block text-sm font-medium text-gray-700 mb-1">Content</label> | |
| <div class="editor-toolbar bg-gray-100 p-2"> | |
| <div class="flex flex-wrap items-center space-x-1"> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="bold"><i class="fas fa-bold"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="italic"><i class="fas fa-italic"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="underline"><i class="fas fa-underline"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertUnorderedList"><i class="fas fa-list-ul"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertOrderedList"><i class="fas fa-list-ol"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="createLink"><i class="fas fa-link"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="unlink"><i class="fas fa-unlink"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertImage"><i class="fas fa-image"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="insertVideo"><i class="fas fa-video"></i></button> | |
| <div class="h-5 border-l border-gray-300 mx-1"></div> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="undo"><i class="fas fa-undo"></i></button> | |
| <button type="button" class="editor-btn p-1 hover:bg-gray-200 rounded" data-command="redo"><i class="fas fa-redo"></i></button> | |
| </div> | |
| </div> | |
| <div id="post-content" class="editor-content focus:outline-none focus:ring-2 focus:ring-blue-500" contenteditable="true">{% if post %}{{ post.content | safe }}{% else %}<p>Start writing your post content here...</p>{% endif %}</div> | |
| <input type="hidden" id="post-content-hidden" name="post-content"> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
| <div class="md:col-span-2"> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">Featured Image</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div id="post-featured-image-container" class="border-2 border-dashed border-gray-300 rounded-md p-4 text-center"> | |
| <div id="post-featured-image-preview" class="{% if not post or not post.featured_image %}hidden{% endif %} mb-4"> | |
| <img src="{% if post %}{{ post.featured_image }}{% endif %}" alt="Featured Image" class="image-preview mx-auto"> | |
| </div> | |
| <div id="post-featured-image-upload"> | |
| <i class="fas fa-image text-4xl text-gray-400 mb-2"></i> | |
| <p class="text-sm text-gray-500 mb-2">Drag & drop an image here, or click to select</p> | |
| <button type="button" id="post-upload-featured-image-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md text-sm"> | |
| Select Image | |
| </button> | |
| <input type="text" id="post-featured-image" name="post-featured-image" class="hidden" value="{% if post %}{{ post.featured_image }}{% endif %}"> | |
| </div> | |
| </div> | |
| <div class="mt-2 flex justify-between"> | |
| <button type="button" id="post-remove-featured-image-btn" class="text-red-500 text-sm hover:text-red-700 {% if not post or not post.featured_image %}hidden{% endif %}">Remove Image</button> | |
| <button type="button" id="post-edit-featured-image-btn" class="text-blue-500 text-sm hover:text-blue-700 {% if not post or not post.featured_image %}hidden{% endif %}">Edit Image</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">SEO Settings</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div class="mb-4"> | |
| <label for="post-seo-title" class="block text-sm font-medium text-gray-700 mb-1">SEO Title</label> | |
| <input type="text" id="post-seo-title" name="post-seo-title" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if post %}{{ post.seo_title }}{% endif %}"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="post-seo-description" class="block text-sm font-medium text-gray-700 mb-1">Meta Description</label> | |
| <textarea id="post-seo-description" name="post-seo-description" rows="3" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">{% if post %}{{ post.seo_description }}{% endif %}</textarea> | |
| </div> | |
| <div> | |
| <label for="post-seo-keywords" class="block text-sm font-medium text-gray-700 mb-1">Keywords</label> | |
| <input type="text" id="post-seo-keywords" name="post-seo-keywords" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if post %}{{ post.seo_keywords }}{% endif %}"> | |
| <p class="mt-1 text-xs text-gray-500">Separate keywords with commas</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">Tags</h3> | |
| </div> | |
| <div class="p-4"> | |
| <label for="post-tags" class="block text-sm font-medium text-gray-700 mb-1">Tags</label> | |
| <input type="text" id="post-tags" name="post-tags" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if post %}{{ post.tags }}{% endif %}"> | |
| <p class="mt-1 text-xs text-gray-500">Separate tags with commas</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </form> | |
| </div> | |
| <!-- Case Studies Section --> | |
| <div id="cases-section" class="section-content" {% if section != 'cases-section' %}style="display: none;"{% endif %}> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">Case Studies</h2> | |
| <a href="{{ url_for('add_case') }}" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-plus mr-2"></i> New Case Study | |
| </a> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="flex flex-col md:flex-row md:items-center md:justify-between"> | |
| <div class="relative mb-4 md:mb-0 md:w-64"> | |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <i class="fas fa-search text-gray-400"></i> | |
| </div> | |
| <input type="text" id="cases-search" class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" placeholder="Search case studies..."> | |
| </div> | |
| <div class="flex items-center space-x-2"> | |
| <select id="cases-filter" class="block w-full md:w-auto pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="all">All Cases</option> | |
| <option value="published">Published</option> | |
| <option value="draft">Draft</option> | |
| </select> | |
| <select id="cases-category-filter" class="block w-full md:w-auto pl-3 pr-10 py-2 text-base border border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="all">All Categories</option> | |
| <option value="orthodontics">Orthodontics</option> | |
| <option value="cosmetic">Cosmetic Dentistry</option> | |
| <option value="implants">Implants</option> | |
| </select> | |
| <button id="cases-bulk-actions" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| Bulk Actions | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> | |
| <input type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| </th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Title</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Treatment</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th> | |
| <th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| {% if cases %} | |
| {% for case in cases %} | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap"> | |
| <input type="checkbox" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
| </td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ case.title }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ case.treatment }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ case.status }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap">{{ case.date }}</td> | |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> | |
| <a href="{{ url_for('edit_case', id=case.id) }}" class="text-blue-500 hover:text-blue-700">Edit</a> | |
| <a href="{{ url_for('delete_case', id=case.id) }}" class="text-red-500 hover:text-red-700 ml-4">Delete</a> | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| {% else %} | |
| <tr> | |
| <td colspan="6" class="px-6 py-4 text-center text-gray-500">No case studies available</td> | |
| </tr> | |
| {% endif %} | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Case Editor Section --> | |
| <div id="case-editor-section" class="section-content" {% if section != 'case-editor-section' %}style="display: none;"{% endif %}> | |
| <form method="POST" action="{% if case %}{{ url_for('edit_case', id=case.id) }}{% else %}{{ url_for('add_case') }}{% endif %}" enctype="multipart/form-data"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-2xl font-bold">{% if case %}Edit Case Study{% else %}New Case Study{% endif %}</h2> | |
| <div class="flex space-x-2"> | |
| <button type="submit" name="preview" class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-eye mr-2"></i> Preview | |
| </button> | |
| <button type="submit" name="save" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center"> | |
| <i class="fas fa-save mr-2"></i> Save | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div> | |
| <label for="case-title" class="block text-sm font-medium text-gray-700 mb-1">Case Title</label> | |
| <input type="text" id="case-title" name="case-title" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.title }}{% endif %}" required> | |
| </div> | |
| <div> | |
| <label for="case-treatment" class="block text-sm font-medium text-gray-700 mb-1">Treatment</label> | |
| <input type="text" id="case-treatment" name="case-treatment" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.treatment }}{% endif %}" required> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4 border-b border-gray-200"> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div> | |
| <label for="case-status" class="block text-sm font-medium text-gray-700 mb-1">Status</label> | |
| <select id="case-status" name="case-status" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="draft" {% if case and case.status == 'draft' %}selected{% endif %}>Draft</option> | |
| <option value="published" {% if case and case.status == 'published' %}selected{% endif %}>Published</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label for="case-date" class="block text-sm font-medium text-gray-700 mb-1">Date</label> | |
| <input type="date" id="case-date" name="case-date" class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.date }}{% endif %}" required> | |
| </div> | |
| <div> | |
| <label for="case-category" class="block text-sm font-medium text-gray-700 mb-1">Category</label> | |
| <select id="case-category" name="case-category" class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"> | |
| <option value="orthodontics" {% if case and case.category == 'orthodontics' %}selected{% endif %}>Orthodontics</option> | |
| <option value="cosmetic" {% if case and case.category == 'cosmetic' %}selected{% endif %}>Cosmetic Dentistry</option> | |
| <option value="implants" {% if case and case.category == 'implants' %}selected{% endif %}>Implants</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4"> | |
| <label for="case-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label> | |
| <textarea id="case-description" name="case-description" rows="5" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">{% if case %}{{ case.description }}{% endif %}</textarea> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
| <div class="md:col-span-2"> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">Images</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div> | |
| <label for="case-before-image" class="block text-sm font-medium text-gray-700 mb-1">Before Image</label> | |
| <input type="file" id="case-before-image" name="case-before-image" accept="image/*" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm mb-2"> | |
| <div class="border-2 border-dashed border-gray-300 rounded-md p-4 text-center"> | |
| <div id="before-image-preview" class="{% if not case or not case.before_image %}hidden{% endif %} mb-4"> | |
| <img src="{% if case %}{{ case.before_image }}{% endif %}" alt="Before Image" class="image-preview mx-auto"> | |
| </div> | |
| <div id="before-image-upload"> | |
| <i class="fas fa-image text-4xl text-gray-400 mb-2"></i> | |
| <p class="text-sm text-gray-500 mb-2">Drag & drop or click to upload</p> | |
| <button type="button" id="upload-before-image-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md text-sm">Select Image</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <label for="case-after-image" class="block text-sm font-medium text-gray-700 mb-1">After Image</label> | |
| <input type="file" id="case-after-image" name="case-after-image" accept="image/*" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm mb-2"> | |
| <div class="border-2 border-dashed border-gray-300 rounded-md p-4 text-center"> | |
| <div id="after-image-preview" class="{% if not case or not case.after_image %}hidden{% endif %} mb-4"> | |
| <img src="{% if case %}{{ case.after_image }}{% endif %}" alt="After Image" class="image-preview mx-auto"> | |
| </div> | |
| <div id="after-image-upload"> | |
| <i class="fas fa-image text-4xl text-gray-400 mb-2"></i> | |
| <p class="text-sm text-gray-500 mb-2">Drag & drop or click to upload</p> | |
| <button type="button" id="upload-after-image-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md text-sm">Select Image</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">Patient Information</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> | |
| <div> | |
| <label for="case-patient-name" class="block text-sm font-medium text-gray-700 mb-1">Patient Name</label> | |
| <input type="text" id="case-patient-name" name="case-patient-name" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.patient_name }}{% endif %}"> | |
| </div> | |
| <div> | |
| <label for="case-patient-age" class="block text-sm font-medium text-gray-700 mb-1">Patient Age</label> | |
| <input type="number" id="case-patient-age" name="case-patient-age" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.patient_age }}{% endif %}"> | |
| </div> | |
| <div> | |
| <label for="case-patient-rating" class="block text-sm font-medium text-gray-700 mb-1">Patient Rating</label> | |
| <input type="number" id="case-patient-rating" name="case-patient-rating" min="1" max="5" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.patient_rating }}{% else %}5{% endif %}"> | |
| </div> | |
| <div> | |
| <label for="case-patient-avatar" class="block text-sm font-medium text-gray-700 mb-1">Patient Avatar</label> | |
| <input type="file" id="case-patient-avatar" name="case-patient-avatar" accept="image/*" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm mb-2"> | |
| <div class="border-2 border-dashed border-gray-300 rounded-md p-4 text-center"> | |
| <div id="patient-avatar-preview" class="{% if not case or not case.patient_avatar %}hidden{% endif %} mb-4"> | |
| <img src="{% if case %}{{ case.patient_avatar }}{% endif %}" alt="Patient Avatar" class="image-preview mx-auto"> | |
| </div> | |
| <div id="patient-avatar-upload"> | |
| <i class="fas fa-user-circle text-4xl text-gray-400 mb-2"></i> | |
| <p class="text-sm text-gray-500 mb-2">Drag & drop or click to upload</p> | |
| <button type="button" id="upload-patient-avatar-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md text-sm">Select Avatar</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden mb-6"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">SEO Settings</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div class="mb-4"> | |
| <label for="case-seo-title" class="block text-sm font-medium text-gray-700 mb-1">SEO Title</label> | |
| <input type="text" id="case-seo-title" name="case-seo-title" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.seo_title }}{% endif %}"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="case-seo-description" class="block text-sm font-medium text-gray-700 mb-1">Meta Description</label> | |
| <textarea id="case-seo-description" name="case-seo-description" rows="3" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm">{% if case %}{{ case.seo_description }}{% endif %}</textarea> | |
| </div> | |
| <div> | |
| <label for="case-seo-keywords" class="block text-sm font-medium text-gray-700 mb-1">Keywords</label> | |
| <input type="text" id="case-seo-keywords" name="case-seo-keywords" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.seo_keywords }}{% endif %}"> | |
| <p class="mt-1 text-xs text-gray-500">Separate keywords with commas</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow overflow-hidden"> | |
| <div class="p-4 border-b border-gray-200"> | |
| <h3 class="text-lg font-medium">Additional Details</h3> | |
| </div> | |
| <div class="p-4"> | |
| <div class="mb-4"> | |
| <label for="case-id" class="block text-sm font-medium text-gray-700 mb-1">Case ID</label> | |
| <input type="text" id="case-id" name="case-id" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.case_id }}{% endif %}" required> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="case-duration" class="block text-sm font-medium text-gray-700 mb-1">Duration</label> | |
| <input type="text" id="case-duration" name="case-duration" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.duration }}{% endif %}"> | |
| </div> | |
| <div class="mb-4"> | |
| <label for="case-visits" class="block text-sm font-medium text-gray-700 mb-1">Visits</label> | |
| <input type="number" id="case-visits" name="case-visits" class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm" value="{% if case %}{{ case.visits }}{% endif %}"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </form> | |
| </div> |