-
{% trans "Click Statistics" %}
+ {% if link.link_type == 'CUSTOM' %}
+
+
+
{% trans "Custom Content" %}
+
+
+
+ {{ rendered_text|safe }}
+
+
-
- {% if click_stats != '[]' %}
-
-
+ {% endif %}
+
+
+
+
{% trans "Click Statistics" %}
+
+
+
-
-
- {% else %}
-
{% trans "No click data available yet." %}
- {% endif %}
-
{% endblock %}
{% block extra_js %}
+
{% endblock %}
+
+{% block extra_css %}
+
+{% endblock %}
diff --git a/links/views.py b/links/views.py
index aa73b78..62fbb04 100644
--- a/links/views.py
+++ b/links/views.py
@@ -16,6 +16,7 @@ from django.http import JsonResponse, HttpResponse
from django.core.serializers import serialize
import random
from django.utils.text import slugify
+import markdown
class LinkListView(ListView):
model = Link
@@ -161,12 +162,17 @@ class LinkDetailView(DetailView):
date=TruncDate('clicked_at')
).values('date').annotate(count=Count('id')).order_by('date')
- # 将查询结果转换为列表,并将日期转换为字符串
+ # Convert query results to list and format dates as strings
click_stats_list = list(click_stats)
for item in click_stats_list:
item['date'] = item['date'].strftime('%Y-%m-%d')
context['click_stats'] = json.dumps(click_stats_list, cls=DjangoJSONEncoder)
+
+ # Convert markdown to HTML if the link is a custom type
+ if self.object.link_type == Link.LinkType.CUSTOM:
+ context['rendered_text'] = markdown.markdown(self.object.text)
+
return context
def search_aliases(request):
diff --git a/new_theme/static/css/dist/styles.css b/new_theme/static/css/dist/styles.css
index 085ebea..4c0c221 100644
--- a/new_theme/static/css/dist/styles.css
+++ b/new_theme/static/css/dist/styles.css
@@ -729,6 +729,10 @@ video {
margin-left: 0.5rem;
}
+.mr-1 {
+ margin-right: 0.25rem;
+}
+
.block {
display: block;
}
@@ -817,6 +821,10 @@ video {
max-width: 20rem;
}
+.max-w-none {
+ max-width: none;
+}
+
.flex-grow {
flex-grow: 1;
}
@@ -875,6 +883,15 @@ video {
gap: 1rem;
}
+.gap-x-4 {
+ -moz-column-gap: 1rem;
+ column-gap: 1rem;
+}
+
+.gap-y-8 {
+ row-gap: 2rem;
+}
+
.space-x-3 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.75rem * var(--tw-space-x-reverse));
@@ -1087,6 +1104,16 @@ video {
background-color: rgb(240 253 244 / var(--tw-bg-opacity));
}
+.bg-blue-100 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(219 234 254 / var(--tw-bg-opacity));
+}
+
+.bg-green-100 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(220 252 231 / var(--tw-bg-opacity));
+}
+
.p-2 {
padding: 0.5rem;
}
@@ -1139,6 +1166,16 @@ video {
padding-bottom: 1.25rem;
}
+.px-2\.5 {
+ padding-left: 0.625rem;
+ padding-right: 0.625rem;
+}
+
+.py-0\.5 {
+ padding-top: 0.125rem;
+ padding-bottom: 0.125rem;
+}
+
.text-left {
text-align: left;
}
@@ -1288,6 +1325,20 @@ video {
color: rgb(21 128 61 / var(--tw-text-opacity));
}
+.text-blue-800 {
+ --tw-text-opacity: 1;
+ color: rgb(30 64 175 / var(--tw-text-opacity));
+}
+
+.text-green-800 {
+ --tw-text-opacity: 1;
+ color: rgb(22 101 52 / var(--tw-text-opacity));
+}
+
+.underline {
+ text-decoration-line: underline;
+}
+
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
@@ -1565,6 +1616,14 @@ video {
}
@media (min-width: 640px) {
+ .sm\:col-span-1 {
+ grid-column: span 1 / span 1;
+ }
+
+ .sm\:col-span-2 {
+ grid-column: span 2 / span 2;
+ }
+
.sm\:inline {
display: inline;
}
diff --git a/requirements.txt b/requirements.txt
index f930391..82c78a0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,4 +9,5 @@ django-tailwind==3.8.0
fontawesome-free==5.15.3
gunicorn==22.0.0
whitenoise==5.3.0
-django-simplemde-x==1.2.0
+django-simplemde==0.1.4
+markdown==3.7