mirror of
https://github.com/wahyd4/links.git
synced 2026-08-08 21:04:53 +10:00
Update style for post and link details
This commit is contained in:
@@ -3,220 +3,211 @@
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto px-2 py-2">
|
||||
<div class="bg-white shadow-md rounded-lg overflow-hidden mb-8">
|
||||
<div class="px-2 py-5 sm:px-6 bg-gray-50 border-b border-gray-200 flex items-center justify-between">
|
||||
<h1 class="text-2xl font-bold text-gray-900 flex items-center">
|
||||
{% trans "Link Details" %}
|
||||
<div class="apple-wrap link-detail-wrap">
|
||||
|
||||
<!-- Header + metadata card -->
|
||||
<div class="apple-card">
|
||||
<div class="link-header-row">
|
||||
<div class="link-type-badge-row">
|
||||
<h1 class="link-detail-title">{% trans "Link Details" %}</h1>
|
||||
{% if '{' in link.original_url and '}' in link.original_url %}
|
||||
<span class="ml-2 bg-purple-100 text-purple-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded-full flex items-center">
|
||||
<i class="fas fa-magic mr-1"></i>{% trans "Template" %}
|
||||
</span>
|
||||
<span class="badge badge-template"><i class="fas fa-magic" aria-hidden="true"></i>{% trans "Template" %}</span>
|
||||
{% elif link.link_type == 'LINK' %}
|
||||
<span class="ml-2 bg-blue-100 text-blue-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded-full flex items-center">
|
||||
<i class="fas fa-link mr-1"></i>{% trans "Link" %}
|
||||
</span>
|
||||
<span class="badge badge-link"><i class="fas fa-link" aria-hidden="true"></i>{% trans "Link" %}</span>
|
||||
{% else %}
|
||||
<span class="ml-2 bg-green-100 text-green-800 text-xs font-medium mr-2 px-2.5 py-0.5 rounded-full flex items-center">
|
||||
<i class="fas fa-code mr-1"></i>{% trans "Custom" %}
|
||||
</span>
|
||||
<span class="badge badge-custom"><i class="fas fa-code" aria-hidden="true"></i>{% trans "Custom" %}</span>
|
||||
{% endif %}
|
||||
</h1>
|
||||
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-2">
|
||||
<a href="{% url 'redirect_to_original' link.alias %}" target="_blank" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-2 rounded text-sm sm:text-base inline-flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
</div>
|
||||
<div class="link-header-actions">
|
||||
<a href="{% url 'redirect_to_original' link.alias %}" target="_blank" class="action-btn action-btn-green">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
|
||||
</svg>
|
||||
{% trans "Go to link" %}
|
||||
</a>
|
||||
<a href="{% url 'link_update' link.pk %}" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-2 rounded text-sm sm:text-base inline-flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<a href="{% url 'link_update' link.pk %}" class="action-btn action-btn-blue">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
||||
</svg>
|
||||
{% trans "Edit" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-2 py-5 sm:p-6">
|
||||
<dl class="grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2">
|
||||
<div class="sm:col-span-1">
|
||||
<dt class="text-sm font-medium text-gray-500">{% trans "Alias" %}</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">{{ link.alias }}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-1">
|
||||
<dt class="text-sm font-medium text-gray-500">{% trans "Click Count" %}</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">{{ link.click_count }}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-1">
|
||||
<dt class="text-sm font-medium text-gray-500">{% trans "Created At" %}</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">{{ link.created_at|date:"Y-m-d H:i" }}</dd>
|
||||
</div>
|
||||
<div class="sm:col-span-1">
|
||||
<dt class="text-sm font-medium text-gray-500">{% trans "Updated At" %}</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">{{ link.updated_at|date:"Y-m-d H:i" }}</dd>
|
||||
</div>
|
||||
{% if link.link_type == 'LINK' %}
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="text-sm font-medium text-gray-500">{% trans "Original URL" %}</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">
|
||||
<a href="{{ link.original_url }}" target="_blank" class="text-blue-600 hover:underline">{{ link.original_url }}</a>
|
||||
</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if link.description %}
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="text-sm font-medium text-gray-500">{% trans "Description" %}</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900">{{ link.description }}</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if link.tags.exists %}
|
||||
<div class="sm:col-span-2">
|
||||
<dt class="text-sm font-medium text-gray-500">{% trans "Tags" %}</dt>
|
||||
<dd class="mt-1">
|
||||
<div class="flex flex-wrap gap-2 mt-2">
|
||||
{% for tag in link.tags.all %}
|
||||
{% with number=forloop.counter %}
|
||||
<a href="{% url 'tag-detail' tag.slug %}"
|
||||
class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium transition duration-150 {% if number|divisibleby:10 %}tag-10{% elif number|divisibleby:9 %}tag-9{% elif number|divisibleby:8 %}tag-8{% elif number|divisibleby:7 %}tag-7{% elif number|divisibleby:6 %}tag-6{% elif number|divisibleby:5 %}tag-5{% elif number|divisibleby:4 %}tag-4{% elif number|divisibleby:3 %}tag-3{% elif number|divisibleby:2 %}tag-2{% else %}tag-1{% endif %}">
|
||||
{{ tag.name }}
|
||||
</a>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<dl class="link-meta-grid">
|
||||
<div class="link-meta-item">
|
||||
<dt>{% trans "Alias" %}</dt>
|
||||
<dd>{{ link.alias }}</dd>
|
||||
</div>
|
||||
<div class="link-meta-item">
|
||||
<dt>{% trans "Click Count" %}</dt>
|
||||
<dd>{{ link.click_count }}</dd>
|
||||
</div>
|
||||
<div class="link-meta-item">
|
||||
<dt>{% trans "Created At" %}</dt>
|
||||
<dd>{{ link.created_at|date:"Y-m-d H:i" }}</dd>
|
||||
</div>
|
||||
<div class="link-meta-item">
|
||||
<dt>{% trans "Updated At" %}</dt>
|
||||
<dd>{{ link.updated_at|date:"Y-m-d H:i" }}</dd>
|
||||
</div>
|
||||
{% if link.link_type == 'LINK' %}
|
||||
<div class="link-meta-item span-2">
|
||||
<dt>{% trans "Original URL" %}</dt>
|
||||
<dd>
|
||||
<a href="{{ link.original_url }}" target="_blank">{{ link.original_url }}</a>
|
||||
</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if link.description %}
|
||||
<div class="link-meta-item span-2">
|
||||
<dt>{% trans "Description" %}</dt>
|
||||
<dd>{{ link.description }}</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if link.tags.exists %}
|
||||
<div class="link-meta-item span-2">
|
||||
<dt>{% trans "Tags" %}</dt>
|
||||
<dd>
|
||||
<div class="link-meta-tags">
|
||||
{% for tag in link.tags.all %}
|
||||
{% with number=forloop.counter %}
|
||||
<a href="{% url 'tag-detail' tag.slug %}"
|
||||
class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium transition duration-150 {% if number|divisibleby:10 %}tag-10{% elif number|divisibleby:9 %}tag-9{% elif number|divisibleby:8 %}tag-8{% elif number|divisibleby:7 %}tag-7{% elif number|divisibleby:6 %}tag-6{% elif number|divisibleby:5 %}tag-5{% elif number|divisibleby:4 %}tag-4{% elif number|divisibleby:3 %}tag-3{% elif number|divisibleby:2 %}tag-2{% else %}tag-1{% endif %}">
|
||||
{{ tag.name }}
|
||||
</a>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
{% if link.link_type == 'CUSTOM' %}
|
||||
<div class="bg-white shadow-md rounded-lg overflow-hidden mb-8">
|
||||
<div class="px-2 py-5 sm:px-6 bg-gray-50 border-b border-gray-200">
|
||||
<h2 class="text-xl font-bold text-gray-900">{% trans "Custom Content" %}</h2>
|
||||
</div>
|
||||
<div class="px-2 py-5 sm:p-6">
|
||||
<div class="prose prose-sm sm:prose lg:prose-lg xl:prose-xl max-w-none">
|
||||
{{ rendered_text|safe }}
|
||||
</div>
|
||||
<div class="apple-card section-spacing">
|
||||
<h2 class="section-title-sm mb-4">{% trans "Custom Content" %}</h2>
|
||||
<div class="prose prose-sm sm:prose lg:prose-lg xl:prose-xl max-w-none">
|
||||
{{ rendered_text|safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="bg-white shadow-md rounded-lg overflow-hidden">
|
||||
<div class="px-2 py-5 sm:px-6 bg-gray-50 border-b border-gray-200">
|
||||
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center space-y-4 sm:space-y-0">
|
||||
<h2 class="text-xl font-bold text-gray-900">{% trans "Click Statistics" %} - {{ period_name }}</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button onclick="changePeriod('3m')" class="period-btn {% if current_period == '3m' %}active{% endif %}" data-period="3m">
|
||||
{% trans "3 Months" %}
|
||||
</button>
|
||||
<button onclick="changePeriod('6m')" class="period-btn {% if current_period == '6m' %}active{% endif %}" data-period="6m">
|
||||
{% trans "6 Months" %}
|
||||
</button>
|
||||
<button onclick="changePeriod('1y')" class="period-btn {% if current_period == '1y' %}active{% endif %}" data-period="1y">
|
||||
{% trans "1 Year" %}
|
||||
</button>
|
||||
<button onclick="changePeriod('all')" class="period-btn {% if current_period == 'all' %}active{% endif %}" data-period="all">
|
||||
{% trans "All Time" %}
|
||||
</button>
|
||||
</div>
|
||||
<div class="apple-card section-spacing">
|
||||
<div class="stats-header">
|
||||
<h2 class="section-title-sm">{% trans "Click Statistics" %} - {{ period_name }}</h2>
|
||||
<div class="period-toggle-group">
|
||||
<button onclick="changePeriod('3m')" class="period-btn {% if current_period == '3m' %}active{% endif %}" data-period="3m">
|
||||
{% trans "3 Months" %}
|
||||
</button>
|
||||
<button onclick="changePeriod('6m')" class="period-btn {% if current_period == '6m' %}active{% endif %}" data-period="6m">
|
||||
{% trans "6 Months" %}
|
||||
</button>
|
||||
<button onclick="changePeriod('1y')" class="period-btn {% if current_period == '1y' %}active{% endif %}" data-period="1y">
|
||||
{% trans "1 Year" %}
|
||||
</button>
|
||||
<button onclick="changePeriod('all')" class="period-btn {% if current_period == 'all' %}active{% endif %}" data-period="all">
|
||||
{% trans "All Time" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-2 py-5 sm:p-6">
|
||||
<div style="height: 400px; position: relative;">
|
||||
<canvas id="clickChart"></canvas>
|
||||
</div>
|
||||
<div style="height: 400px; position: relative;">
|
||||
<canvas id="clickChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white shadow-md rounded-lg overflow-hidden mt-8">
|
||||
<div class="px-2 py-5 sm:px-6 bg-gray-50 border-b border-gray-200">
|
||||
<h2 class="text-xl font-bold text-gray-900">{% trans "Change History" %}</h2>
|
||||
</div>
|
||||
<div class="px-2 py-5 sm:p-6">
|
||||
{% if change_logs %}
|
||||
<ul class="divide-y divide-gray-200">
|
||||
{% for log in change_logs %}
|
||||
<li class="py-3">
|
||||
{% if log.change_type == 'url_change' %}
|
||||
<div class="flex items-center mb-2">
|
||||
<svg class="w-5 h-5 text-blue-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path>
|
||||
</svg>
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
{% trans "URL Changed" %}
|
||||
</p>
|
||||
<span class="ml-2 text-xs text-gray-500">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
<div class="apple-card section-spacing">
|
||||
<h2 class="section-title-sm mb-4">{% trans "Change History" %}</h2>
|
||||
{% if change_logs %}
|
||||
<ul class="change-log-list">
|
||||
{% for log in change_logs %}
|
||||
<li class="change-log-item">
|
||||
{% if log.change_type == 'url_change' %}
|
||||
<div class="change-icon change-icon-blue">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="change-log-body">
|
||||
<div class="change-log-title-row">
|
||||
<p class="change-log-title">{% trans "URL Changed" %}</p>
|
||||
<span class="change-log-time">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
{% if log.old_url %}
|
||||
<p class="mt-1 text-sm text-red-600 line-through ml-7">{{ log.old_url }}</p>
|
||||
<p class="change-log-detail change-url-old">{{ log.old_url }}</p>
|
||||
{% endif %}
|
||||
{% if log.new_url %}
|
||||
<p class="mt-1 text-sm text-green-600 ml-7">{{ log.new_url }}</p>
|
||||
<p class="change-log-detail change-url-new">{{ log.new_url }}</p>
|
||||
{% endif %}
|
||||
{% elif log.change_type == 'task_toggle' %}
|
||||
<div class="flex items-center mb-2">
|
||||
<svg class="w-5 h-5 text-purple-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path>
|
||||
</svg>
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
{% trans "Task Toggled" %}
|
||||
</p>
|
||||
<span class="ml-2 text-xs text-gray-500">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
{% elif log.change_type == 'task_toggle' %}
|
||||
<div class="change-icon change-icon-purple">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="change-log-body">
|
||||
<div class="change-log-title-row">
|
||||
<p class="change-log-title">{% trans "Task Toggled" %}</p>
|
||||
<span class="change-log-time">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
{% if log.metadata %}
|
||||
<div class="ml-7 text-sm">
|
||||
<div class="change-log-detail">
|
||||
{% if log.metadata.task_text %}
|
||||
<p class="text-gray-700 font-medium mb-1">
|
||||
<p style="font-weight: 500; color: var(--apple-text); margin-bottom: 0.25rem;">
|
||||
"{{ log.metadata.task_text }}"
|
||||
</p>
|
||||
{% endif %}
|
||||
<p class="text-gray-600">
|
||||
<span class="{% if log.metadata.old_state %}text-green-600{% else %}text-gray-400{% endif %}">
|
||||
<p>
|
||||
<span class="{% if log.metadata.old_state %}change-url-new{% else %}change-log-time{% endif %}">
|
||||
{% if log.metadata.old_state %}☑{% else %}☐{% endif %}
|
||||
</span>
|
||||
→
|
||||
<span class="{% if log.metadata.new_state %}text-green-600{% else %}text-gray-400{% endif %}">
|
||||
<span class="{% if log.metadata.new_state %}change-url-new{% else %}change-log-time{% endif %}">
|
||||
{% if log.metadata.new_state %}☑{% else %}☐{% endif %}
|
||||
</span>
|
||||
<span class="ml-1">{% if log.metadata.new_state %}{% trans "checked" %}{% else %}{% trans "unchecked" %}{% endif %}</span>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% elif log.change_type == 'content_edit' %}
|
||||
<div class="flex items-center mb-2">
|
||||
<svg class="w-5 h-5 text-green-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
||||
</svg>
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
{% trans "Content Edited" %}
|
||||
</p>
|
||||
<span class="ml-2 text-xs text-gray-500">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
{% elif log.change_type == 'content_edit' %}
|
||||
<div class="change-icon change-icon-green">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="change-log-body">
|
||||
<div class="change-log-title-row">
|
||||
<p class="change-log-title">{% trans "Content Edited" %}</p>
|
||||
<span class="change-log-time">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
{% if log.metadata %}
|
||||
<div class="ml-7 text-sm text-gray-600">
|
||||
<div class="change-log-detail">
|
||||
{{ log.metadata|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="flex items-center mb-2">
|
||||
<svg class="w-5 h-5 text-gray-500 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
{% trans "Change" %}
|
||||
</p>
|
||||
<span class="ml-2 text-xs text-gray-500">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="change-icon change-icon-gray">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="change-log-body">
|
||||
<div class="change-log-title-row">
|
||||
<p class="change-log-title">{% trans "Change" %}</p>
|
||||
<span class="change-log-time">{{ log.changed_at|date:"Y-m-d H:i" }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="text-sm text-gray-600">{% trans "No changes recorded." %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p class="empty-history">{% trans "No changes recorded." %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -255,17 +246,17 @@
|
||||
datasets: [{
|
||||
label: '{% trans "Clicks" %}',
|
||||
data: clickData.map(item => item.count),
|
||||
backgroundColor: 'rgba(99, 102, 241, 0.1)',
|
||||
borderColor: 'rgba(99, 102, 241, 1)',
|
||||
backgroundColor: 'rgba(0, 113, 227, 0.08)',
|
||||
borderColor: 'rgba(0, 113, 227, 1)',
|
||||
borderWidth: 3,
|
||||
fill: true,
|
||||
tension: 0.4,
|
||||
pointBackgroundColor: 'rgba(99, 102, 241, 1)',
|
||||
pointBackgroundColor: 'rgba(0, 113, 227, 1)',
|
||||
pointBorderColor: '#ffffff',
|
||||
pointBorderWidth: 2,
|
||||
pointRadius: 4,
|
||||
pointHoverRadius: 6,
|
||||
pointHoverBackgroundColor: 'rgba(99, 102, 241, 1)',
|
||||
pointHoverBackgroundColor: 'rgba(0, 113, 227, 1)',
|
||||
pointHoverBorderColor: '#ffffff',
|
||||
pointHoverBorderWidth: 2
|
||||
}]
|
||||
@@ -376,124 +367,228 @@
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.prose {
|
||||
color: #374151;
|
||||
max-width: 65ch;
|
||||
}
|
||||
.prose p {
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
.prose a {
|
||||
color: #2563eb;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.prose strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
.prose ul {
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
list-style-type: disc;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
.prose ol {
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
list-style-type: decimal;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
.prose h1 {
|
||||
font-size: 2.25em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.8888889em;
|
||||
line-height: 1.1111111;
|
||||
}
|
||||
.prose h2 {
|
||||
font-size: 1.5em;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1em;
|
||||
line-height: 1.3333333;
|
||||
}
|
||||
.prose h3 {
|
||||
font-size: 1.25em;
|
||||
margin-top: 1.6em;
|
||||
margin-bottom: 0.6em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.prose img {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
.prose code {
|
||||
color: #111827;
|
||||
font-weight: 600;
|
||||
}
|
||||
.prose pre {
|
||||
color: #e5e7eb;
|
||||
background-color: #1f2937;
|
||||
overflow-x: auto;
|
||||
font-size: 0.875em;
|
||||
line-height: 1.7142857;
|
||||
margin-top: 1.7142857em;
|
||||
margin-bottom: 1.7142857em;
|
||||
border-radius: 0.375rem;
|
||||
padding-top: 0.8571429em;
|
||||
padding-right: 1.1428571em;
|
||||
padding-bottom: 0.8571429em;
|
||||
padding-left: 1.1428571em;
|
||||
}
|
||||
/* ============================================================
|
||||
Apple-inspired design system — Link detail page
|
||||
Mirrors the home page: #f5f5f7 canvas, SF typography, soft
|
||||
shadows, pill buttons, generous rounded cards.
|
||||
============================================================ */
|
||||
:root {
|
||||
--apple-bg: #f5f5f7;
|
||||
--apple-text: #1d1d1f;
|
||||
--apple-gray: #6e6e73;
|
||||
--apple-blue: #0071e3;
|
||||
--apple-blue-hover: #0077ed;
|
||||
--apple-red: #ff3b30;
|
||||
--apple-green: #1e7b34;
|
||||
--apple-purple: #8944ab;
|
||||
--apple-separator: rgba(0, 0, 0, 0.06);
|
||||
--apple-ease: cubic-bezier(0.28, 0.11, 0.32, 1);
|
||||
--apple-radius-lg: 28px;
|
||||
--apple-radius-md: 22px;
|
||||
--apple-radius-sm: 14px;
|
||||
--apple-shadow-card: 0 4px 24px rgba(0, 0, 0, 0.05);
|
||||
--apple-shadow-lift: 0 18px 44px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
|
||||
/* Chart container styling */
|
||||
#clickChart {
|
||||
border-radius: 8px;
|
||||
}
|
||||
body {
|
||||
background-color: var(--apple-bg) !important;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
||||
"Helvetica Neue", "Segoe UI", Roboto, Arial, sans-serif;
|
||||
color: var(--apple-text);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
/* Period selection buttons */
|
||||
.period-btn {
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid #d1d5db;
|
||||
background-color: #ffffff;
|
||||
color: #374151;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.apple-wrap { max-width: 72rem; margin: 0 auto; }
|
||||
.link-detail-wrap { padding: 0 0.25rem; }
|
||||
|
||||
.period-btn:hover {
|
||||
background-color: #f9fafb;
|
||||
border-color: #9ca3af;
|
||||
}
|
||||
.apple-card {
|
||||
background: #fff;
|
||||
border-radius: var(--apple-radius-lg);
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
box-shadow: var(--apple-shadow-card);
|
||||
padding: clamp(1.25rem, 4vw, 2.25rem);
|
||||
}
|
||||
.section-spacing { margin-top: 1.75rem; }
|
||||
.section-title-sm { font-size: 1.2rem; font-weight: 700; letter-spacing: -0.01em; color: var(--apple-text); }
|
||||
.mb-4 { margin-bottom: 1rem; }
|
||||
|
||||
.period-btn.active {
|
||||
background-color: #6366f1;
|
||||
border-color: #6366f1;
|
||||
color: #ffffff;
|
||||
}
|
||||
/* ---------- Header ---------- */
|
||||
.link-header-row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; }
|
||||
.link-type-badge-row { display: flex; align-items: center; gap: 0.65rem; flex-wrap: wrap; }
|
||||
.link-detail-title { font-size: clamp(1.4rem, 3vw, 1.85rem); font-weight: 700; letter-spacing: -0.02em; color: var(--apple-text); }
|
||||
.link-header-actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
|
||||
|
||||
.period-btn.active:hover {
|
||||
background-color: #5b21b6;
|
||||
border-color: #5b21b6;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex; align-items: center; gap: 0.4rem;
|
||||
padding: 0.28rem 0.72rem; border-radius: 980px;
|
||||
font-size: 0.78rem; font-weight: 600;
|
||||
}
|
||||
.badge-template { background: rgba(191, 90, 242, 0.12); color: #8944ab; }
|
||||
.badge-link { background: rgba(0, 113, 227, 0.10); color: var(--apple-blue); }
|
||||
.badge-custom { background: rgba(48, 209, 88, 0.15); color: #1e7b34; }
|
||||
|
||||
/* Task List Styles */
|
||||
.task-item {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
.action-btn {
|
||||
display: inline-flex; align-items: center; gap: 0.4rem;
|
||||
padding: 0.55rem 1.1rem; border-radius: 980px;
|
||||
font-size: 0.88rem; font-weight: 600; border: none; cursor: pointer;
|
||||
text-decoration: none; white-space: nowrap;
|
||||
transition: background 0.25s var(--apple-ease), color 0.25s var(--apple-ease), transform 0.2s var(--apple-ease);
|
||||
}
|
||||
.action-btn:active { transform: scale(0.96); }
|
||||
.action-btn svg { width: 1rem; height: 1rem; }
|
||||
.action-btn-green { background: rgba(48, 209, 88, 0.14); color: var(--apple-green); }
|
||||
.action-btn-green:hover { background: rgba(48, 209, 88, 0.22); color: var(--apple-green); }
|
||||
.action-btn-blue { background: rgba(0, 113, 227, 0.10); color: var(--apple-blue); }
|
||||
.action-btn-blue:hover { background: rgba(0, 113, 227, 0.18); color: var(--apple-blue); }
|
||||
|
||||
.task-checkbox {
|
||||
margin-right: 0.5rem;
|
||||
cursor: pointer;
|
||||
width: 1.1em;
|
||||
height: 1.1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* ---------- Meta grid ---------- */
|
||||
.link-meta-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem 2rem; }
|
||||
@media (max-width: 640px) { .link-meta-grid { grid-template-columns: 1fr; } }
|
||||
.link-meta-item.span-2 { grid-column: 1 / -1; }
|
||||
.link-meta-item dt { font-size: 0.76rem; font-weight: 600; color: var(--apple-gray); text-transform: uppercase; letter-spacing: 0.07em; margin-bottom: 0.3rem; }
|
||||
.link-meta-item dd { font-size: 0.95rem; color: var(--apple-text); margin: 0; word-break: break-all; }
|
||||
.link-meta-item dd a { color: var(--apple-blue); text-decoration: none; }
|
||||
.link-meta-item dd a:hover { text-decoration: underline; }
|
||||
.link-meta-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
|
||||
.task-checkbox:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
/* ---------- Prose (custom content) ---------- */
|
||||
.prose {
|
||||
color: var(--apple-text);
|
||||
max-width: 65ch;
|
||||
}
|
||||
.prose p {
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
}
|
||||
.prose a {
|
||||
color: var(--apple-blue);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.prose strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
.prose ul {
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
list-style-type: disc;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
.prose ol {
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
list-style-type: decimal;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
.prose h1 {
|
||||
font-size: 2.25em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.8888889em;
|
||||
line-height: 1.1111111;
|
||||
}
|
||||
.prose h2 {
|
||||
font-size: 1.5em;
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1em;
|
||||
line-height: 1.3333333;
|
||||
}
|
||||
.prose h3 {
|
||||
font-size: 1.25em;
|
||||
margin-top: 1.6em;
|
||||
margin-bottom: 0.6em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.prose img {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 2em;
|
||||
border-radius: var(--apple-radius-sm);
|
||||
}
|
||||
.prose code {
|
||||
color: var(--apple-text);
|
||||
font-weight: 600;
|
||||
}
|
||||
.prose pre {
|
||||
color: #e5e7eb;
|
||||
background-color: #1f2937;
|
||||
overflow-x: auto;
|
||||
font-size: 0.875em;
|
||||
line-height: 1.7142857;
|
||||
margin-top: 1.7142857em;
|
||||
margin-bottom: 1.7142857em;
|
||||
border-radius: var(--apple-radius-sm);
|
||||
padding-top: 0.8571429em;
|
||||
padding-right: 1.1428571em;
|
||||
padding-bottom: 0.8571429em;
|
||||
padding-left: 1.1428571em;
|
||||
}
|
||||
|
||||
/* ---------- Click statistics ---------- */
|
||||
.stats-header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; }
|
||||
.period-toggle-group { display: inline-flex; gap: 0.35rem; background: var(--apple-bg); padding: 0.3rem; border-radius: 980px; }
|
||||
.period-btn {
|
||||
padding: 0.45rem 0.95rem;
|
||||
font-size: 0.83rem;
|
||||
font-weight: 600;
|
||||
border-radius: 980px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--apple-gray);
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
.period-btn:hover {
|
||||
color: var(--apple-text);
|
||||
}
|
||||
.period-btn.active {
|
||||
background: #fff;
|
||||
color: var(--apple-blue);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* Chart container styling */
|
||||
#clickChart {
|
||||
border-radius: var(--apple-radius-sm);
|
||||
}
|
||||
|
||||
/* ---------- Change history timeline ---------- */
|
||||
.change-log-list { list-style: none; margin: 0; padding: 0; }
|
||||
.change-log-item { display: flex; gap: 0.9rem; padding: 1rem 0; border-bottom: 1px solid var(--apple-separator); }
|
||||
.change-log-item:last-child { border-bottom: none; padding-bottom: 0; }
|
||||
.change-log-item:first-child { padding-top: 0; }
|
||||
.change-icon {
|
||||
flex-shrink: 0; width: 2.2rem; height: 2.2rem; border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.change-icon svg { width: 1.1rem; height: 1.1rem; }
|
||||
.change-icon-blue { background: rgba(0, 113, 227, 0.10); color: var(--apple-blue); }
|
||||
.change-icon-purple { background: rgba(191, 90, 242, 0.12); color: var(--apple-purple); }
|
||||
.change-icon-green { background: rgba(48, 209, 88, 0.14); color: var(--apple-green); }
|
||||
.change-icon-gray { background: var(--apple-bg); color: var(--apple-gray); }
|
||||
.change-log-body { flex: 1; min-width: 0; }
|
||||
.change-log-title-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
||||
.change-log-title { font-size: 0.92rem; font-weight: 600; color: var(--apple-text); margin: 0; }
|
||||
.change-log-time { font-size: 0.78rem; color: var(--apple-gray); }
|
||||
.change-log-detail { margin-top: 0.35rem; font-size: 0.86rem; color: var(--apple-gray); }
|
||||
.change-url-old { color: var(--apple-red); text-decoration: line-through; }
|
||||
.change-url-new { color: var(--apple-green); }
|
||||
.empty-history { font-size: 0.9rem; color: var(--apple-gray); }
|
||||
|
||||
/* ---------- Task List Styles ---------- */
|
||||
.task-item {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.task-checkbox {
|
||||
margin-right: 0.5rem;
|
||||
cursor: pointer;
|
||||
width: 1.1em;
|
||||
height: 1.1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.task-checkbox:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@@ -6,103 +6,188 @@
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/markdown.css' %}">
|
||||
<style>
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 50;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
.modal.show {
|
||||
display: flex;
|
||||
}
|
||||
.modal-content {
|
||||
background: white;
|
||||
border-radius: 0.75rem;
|
||||
width: 100%;
|
||||
max-width: 28rem;
|
||||
margin: 1rem;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
/* ============================================================
|
||||
Apple-inspired design system — Post detail page
|
||||
Mirrors the home page: #f5f5f7 canvas, SF typography, soft
|
||||
shadows, pill buttons, generous rounded cards.
|
||||
============================================================ */
|
||||
:root {
|
||||
--apple-bg: #f5f5f7;
|
||||
--apple-text: #1d1d1f;
|
||||
--apple-gray: #6e6e73;
|
||||
--apple-blue: #0071e3;
|
||||
--apple-blue-hover: #0077ed;
|
||||
--apple-red: #ff3b30;
|
||||
--apple-green: #1e7b34;
|
||||
--apple-purple: #8944ab;
|
||||
--apple-separator: rgba(0, 0, 0, 0.06);
|
||||
--apple-ease: cubic-bezier(0.28, 0.11, 0.32, 1);
|
||||
--apple-radius-lg: 28px;
|
||||
--apple-radius-md: 22px;
|
||||
--apple-radius-sm: 14px;
|
||||
--apple-shadow-card: 0 4px 24px rgba(0, 0, 0, 0.05);
|
||||
--apple-shadow-lift: 0 18px 44px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
|
||||
/* Think Panel Styles */
|
||||
.think-panel {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
margin: 1rem 0;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
body {
|
||||
background-color: var(--apple-bg) !important;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
|
||||
"Helvetica Neue", "Segoe UI", Roboto, Arial, sans-serif;
|
||||
color: var(--apple-text);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.think-header {
|
||||
background-color: #f9fafb;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 1rem;
|
||||
color: #374151;
|
||||
}
|
||||
.apple-card {
|
||||
background: #fff;
|
||||
border-radius: var(--apple-radius-lg);
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
box-shadow: var(--apple-shadow-card);
|
||||
}
|
||||
|
||||
.think-header:hover {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
.apple-btn {
|
||||
display: inline-flex; align-items: center; justify-content: center; gap: 0.45rem;
|
||||
min-height: 44px; padding: 0.6rem 1.4rem; border-radius: 980px;
|
||||
font-weight: 600; font-size: 0.95rem; border: none; cursor: pointer; text-decoration: none;
|
||||
transition: background 0.3s var(--apple-ease), transform 0.3s var(--apple-ease), box-shadow 0.3s var(--apple-ease);
|
||||
}
|
||||
.apple-btn:active { transform: scale(0.97); }
|
||||
.apple-btn-primary { background: var(--apple-blue); color: #fff; box-shadow: 0 6px 18px rgba(0, 113, 227, 0.28); }
|
||||
.apple-btn-primary:hover { background: var(--apple-blue-hover); color: #fff; }
|
||||
.apple-btn-secondary { background: var(--apple-bg); color: var(--apple-text); border: 1px solid rgba(0, 0, 0, 0.10); }
|
||||
.apple-btn-secondary:hover { background: #ececef; }
|
||||
.apple-btn-danger { background: transparent; color: var(--apple-red); border: 1px solid rgba(255, 59, 48, 0.4); }
|
||||
.apple-btn-danger:hover { background: rgba(255, 59, 48, 0.08); }
|
||||
|
||||
.think-content {
|
||||
padding: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-out, padding 0.3s ease-out;
|
||||
}
|
||||
/* ---------- Soft pill action buttons (Listen / Edit / Share / Delete) ---------- */
|
||||
.action-btn {
|
||||
display: inline-flex; align-items: center; gap: 0.4rem;
|
||||
padding: 0.5rem 1rem; border-radius: 980px;
|
||||
font-size: 0.85rem; font-weight: 600; border: none; cursor: pointer;
|
||||
text-decoration: none; white-space: nowrap;
|
||||
transition: background 0.25s var(--apple-ease), color 0.25s var(--apple-ease), transform 0.2s var(--apple-ease);
|
||||
}
|
||||
.action-btn:active { transform: scale(0.96); }
|
||||
.action-btn svg { width: 1rem; height: 1rem; }
|
||||
.action-btn-purple { background: rgba(191, 90, 242, 0.12); color: var(--apple-purple); }
|
||||
.action-btn-purple:hover { background: rgba(191, 90, 242, 0.20); }
|
||||
.action-btn-blue { background: rgba(0, 113, 227, 0.10); color: var(--apple-blue); }
|
||||
.action-btn-blue:hover { background: rgba(0, 113, 227, 0.18); }
|
||||
.action-btn-green { background: rgba(48, 209, 88, 0.14); color: var(--apple-green); }
|
||||
.action-btn-green:hover { background: rgba(48, 209, 88, 0.22); }
|
||||
.action-btn-red { background: rgba(255, 59, 48, 0.10); color: var(--apple-red); }
|
||||
.action-btn-red:hover { background: rgba(255, 59, 48, 0.18); }
|
||||
.action-btn:disabled { opacity: 0.55; cursor: default; }
|
||||
.action-icon-btn {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
width: 34px; height: 34px; border-radius: 50%; border: none; background: transparent;
|
||||
color: var(--apple-gray); cursor: pointer; transition: background 0.25s ease, color 0.25s ease;
|
||||
}
|
||||
.action-icon-btn:hover { background: rgba(255, 59, 48, 0.10); color: var(--apple-red); }
|
||||
.action-icon-btn:disabled { opacity: 0.5; cursor: default; }
|
||||
.action-icon-btn svg { width: 1rem; height: 1rem; }
|
||||
|
||||
.think-content.expanded {
|
||||
padding: 1rem;
|
||||
max-height: 2000px; /* Adjust based on your needs */
|
||||
transition: max-height 0.5s ease-in, padding 0.3s ease-in;
|
||||
}
|
||||
/* ---------- Modal ---------- */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.45);
|
||||
z-index: 50;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
.modal.show {
|
||||
display: flex;
|
||||
}
|
||||
.modal-content {
|
||||
background: #fff;
|
||||
border-radius: var(--apple-radius-md);
|
||||
width: 100%;
|
||||
max-width: 26rem;
|
||||
margin: 1rem;
|
||||
box-shadow: var(--apple-shadow-lift);
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.think-icon {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
/* Think Panel Styles */
|
||||
.think-panel {
|
||||
border: 1px solid var(--apple-separator);
|
||||
border-radius: var(--apple-radius-sm);
|
||||
margin: 1rem 0;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.think-icon.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.think-header {
|
||||
background-color: var(--apple-bg);
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 1rem;
|
||||
color: var(--apple-text);
|
||||
}
|
||||
|
||||
/* Task List Styles */
|
||||
.task-item {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
.think-header:hover {
|
||||
background-color: #ececef;
|
||||
}
|
||||
|
||||
.task-checkbox {
|
||||
margin-right: 0.5rem;
|
||||
cursor: pointer;
|
||||
width: 1.1em;
|
||||
height: 1.1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.think-content {
|
||||
padding: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-out, padding 0.3s ease-out;
|
||||
}
|
||||
|
||||
.task-checkbox:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.think-content.expanded {
|
||||
padding: 1rem;
|
||||
max-height: 2000px; /* Adjust based on your needs */
|
||||
transition: max-height 0.5s ease-in, padding 0.3s ease-in;
|
||||
}
|
||||
|
||||
/* Enhanced Audio Player Styles */
|
||||
.audio-player {
|
||||
background: linear-gradient(145deg, #f8fafc 0%, #e2e8f0 100%);
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.think-icon {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.think-icon.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Task List Styles */
|
||||
.task-item {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.task-checkbox {
|
||||
margin-right: 0.5rem;
|
||||
cursor: pointer;
|
||||
width: 1.1em;
|
||||
height: 1.1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.task-checkbox:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Enhanced Audio Player Styles */
|
||||
.audio-player {
|
||||
background: linear-gradient(145deg, #fafafa 0%, #eef0f3 100%);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
border-radius: var(--apple-radius-md);
|
||||
box-shadow: var(--apple-shadow-card);
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.audio-controls {
|
||||
display: flex;
|
||||
@@ -307,21 +392,23 @@
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: 1rem;
|
||||
background: #f8fafc;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: var(--apple-radius-sm);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.voice-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
color: var(--apple-text);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.main-content {
|
||||
background: #fff;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
border-radius: var(--apple-radius-lg);
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
box-shadow: var(--apple-shadow-card);
|
||||
padding: clamp(1.25rem, 4vw, 2.5rem);
|
||||
}
|
||||
|
||||
/* ===== Table of Contents Layout ===== */
|
||||
@@ -330,6 +417,34 @@
|
||||
margin: 0.5rem auto;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.post-header-row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 0.85rem; margin-bottom: 1.1rem; }
|
||||
.post-title { font-size: clamp(1.5rem, 3.4vw, 2.1rem); font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; flex: 1 1 16rem; min-width: 0; color: var(--apple-text); }
|
||||
.post-actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; flex-wrap: wrap; }
|
||||
.post-meta { display: flex; flex-direction: column; gap: 0.85rem; margin-bottom: 1.25rem; }
|
||||
.post-summary { position: relative; padding-left: 1rem; border-left: 3px solid rgba(0, 113, 227, 0.35); }
|
||||
.post-summary p { font-size: 1.08rem; color: var(--apple-gray); font-style: italic; margin: 0; }
|
||||
.post-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||
.post-timestamps { display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem; font-size: 0.85rem; color: var(--apple-gray); background: var(--apple-bg); border-radius: 980px; padding: 0.6rem 1.1rem; }
|
||||
.post-timestamps .timestamp-item { display: flex; align-items: center; }
|
||||
.post-timestamps svg { width: 1rem; height: 1rem; margin-right: 0.4rem; color: #a1a1a6; }
|
||||
.post-timestamps .timestamp-label { font-weight: 600; color: var(--apple-text); margin-right: 0.25rem; }
|
||||
.post-article { margin-top: 1.5rem; }
|
||||
.append-section { margin-top: 2.25rem; border-top: 1px solid var(--apple-separator); padding-top: 1.5rem; }
|
||||
.append-title { font-size: 0.85rem; font-weight: 600; color: var(--apple-text); margin-bottom: 0.75rem; }
|
||||
.append-textarea {
|
||||
width: 100%; min-height: 200px; padding: 0.85rem 1rem; font-size: 0.9rem;
|
||||
font-family: 'SF Mono', 'Monaco', 'Menlo', monospace; color: var(--apple-text);
|
||||
background: var(--apple-bg); border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: var(--apple-radius-sm); resize: vertical;
|
||||
transition: border-color 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
|
||||
}
|
||||
.append-textarea:focus {
|
||||
outline: none; background: #fff;
|
||||
border-color: rgba(0, 113, 227, 0.5);
|
||||
box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.14);
|
||||
}
|
||||
.append-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 0.75rem; }
|
||||
.append-status { font-size: 0.78rem; color: var(--apple-gray); }
|
||||
#toc-sidebar {
|
||||
display: none; /* hidden by default (mobile) */
|
||||
}
|
||||
@@ -360,16 +475,21 @@
|
||||
}
|
||||
#toc-sidebar-inner > div {
|
||||
background: #fff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
border-radius: var(--apple-radius-md);
|
||||
box-shadow: var(--apple-shadow-card);
|
||||
padding: 1.25rem;
|
||||
}
|
||||
.toc-card-label {
|
||||
font-size: 0.7rem; font-weight: 600; color: var(--apple-gray);
|
||||
text-transform: uppercase; letter-spacing: 0.09em; margin-bottom: 0.75rem; user-select: none;
|
||||
}
|
||||
|
||||
#toc-sidebar .toc-link {
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.6;
|
||||
color: #6b7280;
|
||||
color: var(--apple-gray);
|
||||
text-decoration: none;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-left: 2px solid transparent;
|
||||
@@ -378,16 +498,16 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
#toc-sidebar .toc-link:hover { color: #1d4ed8; background-color: #eff6ff; }
|
||||
#toc-sidebar .toc-link:hover { color: var(--apple-blue); background-color: rgba(0, 113, 227, 0.08); }
|
||||
#toc-sidebar .toc-link.toc-active {
|
||||
color: #1d4ed8;
|
||||
border-left-color: #1d4ed8;
|
||||
color: var(--apple-blue);
|
||||
border-left-color: var(--apple-blue);
|
||||
font-weight: 500;
|
||||
background-color: #eff6ff;
|
||||
background-color: rgba(0, 113, 227, 0.08);
|
||||
}
|
||||
#toc-sidebar .toc-h2 { font-weight: 500; color: #374151; }
|
||||
#toc-sidebar .toc-h2 { font-weight: 500; color: var(--apple-text); }
|
||||
#toc-sidebar .toc-h3,
|
||||
#toc-sidebar .toc-h4 { font-size: 0.775rem; }
|
||||
|
||||
@@ -397,27 +517,29 @@
|
||||
bottom: 1.5rem;
|
||||
right: 1.5rem;
|
||||
z-index: 40;
|
||||
background: #2563eb;
|
||||
background: var(--apple-blue);
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 9999px;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
box-shadow: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1);
|
||||
box-shadow: 0 12px 28px rgba(0, 113, 227, 0.32);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.15s;
|
||||
transition: background-color 0.2s ease, transform 0.2s var(--apple-ease);
|
||||
}
|
||||
#toc-mobile-btn:hover { background: #1d4ed8; }
|
||||
#toc-mobile-btn:hover { background: var(--apple-blue-hover); transform: translateY(-1px); }
|
||||
|
||||
/* Mobile drawer */
|
||||
#toc-mobile-backdrop {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
-webkit-backdrop-filter: blur(4px);
|
||||
backdrop-filter: blur(4px);
|
||||
z-index: 40;
|
||||
}
|
||||
#toc-mobile-drawer {
|
||||
@@ -429,24 +551,25 @@
|
||||
max-width: 80vw;
|
||||
background: #fff;
|
||||
z-index: 50;
|
||||
box-shadow: 0 25px 50px -12px rgba(0,0,0,.25);
|
||||
box-shadow: var(--apple-shadow-lift);
|
||||
border-radius: 0 var(--apple-radius-md) var(--apple-radius-md) 0;
|
||||
overflow-y: auto;
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.3s ease;
|
||||
transition: transform 0.35s var(--apple-ease);
|
||||
}
|
||||
#toc-nav-mobile .toc-link {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.7;
|
||||
color: #374151;
|
||||
color: var(--apple-text);
|
||||
text-decoration: none;
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-left: 2px solid transparent;
|
||||
transition: color 0.15s, border-color 0.15s;
|
||||
border-radius: 0 4px 4px 0;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
#toc-nav-mobile .toc-link:hover { color: #1d4ed8; background-color: #eff6ff; }
|
||||
#toc-nav-mobile .toc-link.toc-active { color: #1d4ed8; border-left-color: #1d4ed8; font-weight: 500; }
|
||||
#toc-nav-mobile .toc-link:hover { color: var(--apple-blue); background-color: rgba(0, 113, 227, 0.08); }
|
||||
#toc-nav-mobile .toc-link.toc-active { color: var(--apple-blue); border-left-color: var(--apple-blue); font-weight: 500; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@@ -455,23 +578,22 @@
|
||||
<div id="deleteModal" class="modal" aria-labelledby="modal-title" role="dialog" aria-modal="true">
|
||||
<div class="modal-content">
|
||||
<div class="p-6">
|
||||
<h3 class="text-lg font-medium text-gray-900" id="modal-title">
|
||||
<h3 class="text-lg font-semibold" style="color: var(--apple-text);" id="modal-title">
|
||||
{% trans "Delete Post" %}
|
||||
</h3>
|
||||
<p class="mt-2 text-sm text-gray-500">
|
||||
<p class="mt-2 text-sm" style="color: var(--apple-gray);">
|
||||
{% trans "Are you sure you want to delete this post? This action cannot be undone." %}
|
||||
</p>
|
||||
<div class="mt-6 flex space-x-3">
|
||||
<div class="mt-6 flex gap-3">
|
||||
<form method="post" action="{% url 'post-delete' post.pk %}">
|
||||
{% csrf_token %}
|
||||
<button type="submit"
|
||||
class="inline-flex justify-center px-4 py-2 text-sm font-medium text-white bg-red-600 border border-transparent rounded-lg hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition duration-150">
|
||||
<button type="submit" class="apple-btn" style="background: var(--apple-red); color: #fff; box-shadow: 0 6px 18px rgba(255, 59, 48, 0.28);">
|
||||
{% trans "Delete" %}
|
||||
</button>
|
||||
</form>
|
||||
<button type="button"
|
||||
onclick="closeDeleteModal()"
|
||||
class="inline-flex justify-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 transition duration-150">
|
||||
class="apple-btn apple-btn-secondary">
|
||||
{% trans "Cancel" %}
|
||||
</button>
|
||||
</div>
|
||||
@@ -488,7 +610,7 @@
|
||||
<aside id="toc-sidebar">
|
||||
<div id="toc-sidebar-inner">
|
||||
<div>
|
||||
<p style="font-size:0.7rem;font-weight:600;color:#9ca3af;text-transform:uppercase;letter-spacing:0.05em;margin-bottom:0.75rem;user-select:none;">Contents</p>
|
||||
<p class="toc-card-label">{% trans "Contents" %}</p>
|
||||
<nav id="toc-nav"></nav>
|
||||
</div>
|
||||
</div>
|
||||
@@ -496,23 +618,21 @@
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="main-content" id="post-main-content">
|
||||
<!-- Title and Actions - Responsive Layout -->
|
||||
<div class="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 mb-4">
|
||||
<h1 class="text-2xl sm:text-3xl font-bold text-gray-900 sm:flex-1">{{ post.title }}</h1>
|
||||
<!-- Title and Actions -->
|
||||
<div class="post-header-row">
|
||||
<h1 class="post-title">{{ post.title }}</h1>
|
||||
|
||||
<!-- Action Buttons - Responsive positioning -->
|
||||
<div class="flex items-center space-x-2 sm:flex-shrink-0">
|
||||
<button onclick="toggleTTS()"
|
||||
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-purple-700 hover:text-purple-800 bg-purple-50 hover:bg-purple-100 rounded-md transition duration-150">
|
||||
<svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<!-- Action Buttons -->
|
||||
<div class="post-actions">
|
||||
<button onclick="toggleTTS()" class="action-btn action-btn-purple">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M15.536 8.464a5 5 0 010 7.072m2.828-9.9a9 9 0 010 14.142M9 9v6l4-3-4-3z"/>
|
||||
</svg>
|
||||
<span id="tts-button-text">{% trans "Listen" %}</span>
|
||||
</button>
|
||||
<a href="{% url 'post-update' post.pk %}"
|
||||
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-blue-700 hover:text-blue-800 bg-blue-50 hover:bg-blue-100 rounded-md transition duration-150">
|
||||
<svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<a href="{% url 'post-update' post.pk %}" class="action-btn action-btn-blue">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
|
||||
</svg>
|
||||
@@ -523,8 +643,8 @@
|
||||
<!-- Not yet shared -->
|
||||
<button x-show="!isPublic" @click="enableShare()"
|
||||
:disabled="busy"
|
||||
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-green-700 hover:text-green-800 bg-green-50 hover:bg-green-100 rounded-md transition duration-150 disabled:opacity-50">
|
||||
<svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
class="action-btn action-btn-green">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"/>
|
||||
</svg>
|
||||
@@ -532,9 +652,8 @@
|
||||
</button>
|
||||
<!-- Already shared: copy + revoke -->
|
||||
<div x-show="isPublic" class="flex items-center gap-1">
|
||||
<button @click="copyUrl()"
|
||||
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-green-700 bg-green-50 hover:bg-green-100 border border-green-200 rounded-md transition duration-150">
|
||||
<svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<button @click="copyUrl()" class="action-btn action-btn-green">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
|
||||
</svg>
|
||||
@@ -542,16 +661,15 @@
|
||||
</button>
|
||||
<button @click="revokeShare()" :disabled="busy"
|
||||
title="{% trans 'Revoke public access' %}"
|
||||
class="p-1.5 text-gray-400 hover:text-red-500 rounded transition disabled:opacity-50">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
class="action-icon-btn">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="openDeleteModal()"
|
||||
class="inline-flex items-center px-3 py-1.5 text-sm font-medium text-red-700 hover:text-red-800 bg-red-50 hover:bg-red-100 rounded-md transition duration-150">
|
||||
<svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<button onclick="openDeleteModal()" class="action-btn action-btn-red">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
||||
</svg>
|
||||
@@ -561,17 +679,17 @@
|
||||
</div>
|
||||
|
||||
<!-- Metadata -->
|
||||
<div class="space-y-3 mb-4">
|
||||
<div class="post-meta">
|
||||
|
||||
{% if post.summary %}
|
||||
<div class="relative pl-3 border-l-4 border-gray-200">
|
||||
<p class="text-lg text-gray-600 italic">{{ post.summary }}</p>
|
||||
<div class="post-summary">
|
||||
<p>{{ post.summary }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Tags -->
|
||||
{% if post.tags.exists %}
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<div class="post-tags">
|
||||
{% for tag in post.tags.all %}
|
||||
{% with number=forloop.counter %}
|
||||
<a href="{% url 'tag-detail' tag.slug %}"
|
||||
@@ -583,23 +701,23 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Timestamps - Compact single row design -->
|
||||
<div class="flex items-center gap-6 text-sm text-gray-500 bg-gray-50 rounded-md px-3 py-2">
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-1.5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<!-- Timestamps -->
|
||||
<div class="post-timestamps">
|
||||
<div class="timestamp-item">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
<span class="font-medium text-gray-600">{% trans "Created" %}:</span>
|
||||
<time datetime="{{ post.created_at|date:'Y-m-d H:i' }}" class="ml-1">{{ post.created_at|date:"Y-m-d H:i" }}</time>
|
||||
<span class="timestamp-label">{% trans "Created" %}:</span>
|
||||
<time datetime="{{ post.created_at|date:'Y-m-d H:i' }}">{{ post.created_at|date:"Y-m-d H:i" }}</time>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-1.5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div class="timestamp-item">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
||||
</svg>
|
||||
<span class="font-medium text-gray-600">{% trans "Updated" %}:</span>
|
||||
<time datetime="{{ post.updated_at|date:'Y-m-d H:i' }}" class="ml-1">{{ post.updated_at|date:"Y-m-d H:i" }}</time>
|
||||
<span class="timestamp-label">{% trans "Updated" %}:</span>
|
||||
<time datetime="{{ post.updated_at|date:'Y-m-d H:i' }}">{{ post.updated_at|date:"Y-m-d H:i" }}</time>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -607,7 +725,7 @@
|
||||
<!-- TTS Audio Player - Initially Hidden -->
|
||||
<div id="tts-player" class="mt-4 audio-player hidden">
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<h4 class="text-sm font-medium text-gray-800">{% trans "Audio Player" %}</h4>
|
||||
<h4 class="text-sm font-medium" style="color: var(--apple-text);">{% trans "Audio Player" %}</h4>
|
||||
<div id="tts-status" class="audio-status status-ready">{% trans "Ready" %}</div>
|
||||
</div>
|
||||
|
||||
@@ -633,7 +751,7 @@
|
||||
<option value="custom">{% trans "Custom" %}</option>
|
||||
</select>
|
||||
<button onclick="regenerateWithVoice()" id="regenerate-btn"
|
||||
class="px-3 py-1 text-xs font-medium text-purple-700 bg-purple-100 border border-purple-300 rounded-md hover:bg-purple-200 transition-colors duration-200"
|
||||
class="action-btn action-btn-purple"
|
||||
disabled>
|
||||
{% trans "Apply Voice" %}
|
||||
</button>
|
||||
@@ -647,7 +765,7 @@
|
||||
class="custom-voice-input"
|
||||
placeholder="{% trans 'e.g., zh-CN-XiaoxiaoNeural' %}"
|
||||
maxlength="100">
|
||||
<div class="text-xs text-gray-500 mt-1">
|
||||
<div class="text-xs mt-1" style="color: var(--apple-gray);">
|
||||
{% trans "Enter the voice code you want to use" %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -696,21 +814,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Content Section - Full width, no containers -->
|
||||
<article class="prose max-w-none prose-lg">
|
||||
<!-- Content Section -->
|
||||
<article class="prose max-w-none prose-lg post-article">
|
||||
{% markdown_with_tasks post.content post.task_states %}
|
||||
</article>
|
||||
|
||||
<!-- Append Content Section -->
|
||||
<div class="mt-8 border-t border-gray-200 pt-6">
|
||||
<h3 class="text-sm font-semibold text-gray-700 mb-3">{% trans "Append Content" %}</h3>
|
||||
<div class="append-section">
|
||||
<h3 class="append-title">{% trans "Append Content" %}</h3>
|
||||
<textarea id="append-content-input"
|
||||
class="w-full min-h-[200px] px-3 py-2 text-sm font-mono border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-y"
|
||||
class="append-textarea"
|
||||
placeholder="{% trans 'Write markdown to append...' %}"></textarea>
|
||||
<div class="flex items-center justify-between mt-2">
|
||||
<span id="append-status" class="text-xs text-gray-500"></span>
|
||||
<button id="append-btn" onclick="appendContent()"
|
||||
class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors">
|
||||
<div class="append-footer">
|
||||
<span id="append-status" class="append-status"></span>
|
||||
<button id="append-btn" onclick="appendContent()" class="apple-btn apple-btn-primary">
|
||||
{% trans "Append" %}
|
||||
</button>
|
||||
</div>
|
||||
@@ -729,11 +846,11 @@
|
||||
|
||||
<!-- Mobile TOC drawer -->
|
||||
<div id="toc-mobile-drawer">
|
||||
<div style="padding:1rem;">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;padding-bottom:0.75rem;border-bottom:1px solid #f3f4f6;">
|
||||
<p style="font-weight:600;color:#374151;margin:0;">{% trans "Contents" %}</p>
|
||||
<button id="toc-mobile-close" style="background:none;border:none;cursor:pointer;padding:0.25rem;color:#9ca3af;border-radius:0.25rem;" aria-label="Close">
|
||||
<svg width="20" height="20" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<div style="padding:1.25rem;">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1rem;padding-bottom:0.75rem;border-bottom:1px solid var(--apple-separator);">
|
||||
<p style="font-weight:600;color:var(--apple-text);margin:0;">{% trans "Contents" %}</p>
|
||||
<button id="toc-mobile-close" class="action-icon-btn" style="color: var(--apple-gray);" aria-label="Close">
|
||||
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user