Refine media assets and pagination display
@ -1,5 +1,5 @@
|
|||||||
.newsletter-page {
|
.newsletter-page {
|
||||||
background: #0e1b42 url("../img/newsletter_bg.png") center center / cover no-repeat fixed;
|
background: #0e1b42 url("../img/newsletter_bg.webp") center center / cover no-repeat fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.newsletter-page .site-main > .site-container {
|
.newsletter-page .site-main > .site-container {
|
||||||
@ -170,4 +170,4 @@
|
|||||||
.newsletter-back-link__text {
|
.newsletter-back-link__text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
innovedus_cms/base/static/img/email/facebook-white.original.png
Normal file
|
After Width: | Height: | Size: 922 B |
BIN
innovedus_cms/base/static/img/email/instagram-white.original.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
innovedus_cms/base/static/img/email/logo.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
innovedus_cms/base/static/img/email/mailback.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
innovedus_cms/base/static/img/email/threads-white.original.png
Normal file
|
After Width: | Height: | Size: 841 B |
BIN
innovedus_cms/base/static/img/newsletter_bg.webp
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
innovedus_cms/base/static/img/og_default.jpg
Normal file
|
After Width: | Height: | Size: 49 KiB |
@ -1,3 +1,5 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
from django.contrib.syndication.views import Feed
|
from django.contrib.syndication.views import Feed
|
||||||
from django.utils.feedgenerator import Rss201rev2Feed
|
from django.utils.feedgenerator import Rss201rev2Feed
|
||||||
from django.utils.html import strip_tags
|
from django.utils.html import strip_tags
|
||||||
@ -5,6 +7,20 @@ from django.utils.html import strip_tags
|
|||||||
from .models import ArticlePage
|
from .models import ArticlePage
|
||||||
|
|
||||||
|
|
||||||
|
def _get_env_int(name, default):
|
||||||
|
value = os.environ.get(name)
|
||||||
|
if value is None:
|
||||||
|
return default
|
||||||
|
try:
|
||||||
|
parsed = int(value)
|
||||||
|
except ValueError:
|
||||||
|
return default
|
||||||
|
return parsed if parsed > 0 else default
|
||||||
|
|
||||||
|
|
||||||
|
ARTICLE_FEED_SIZE = _get_env_int("ARTICLE_FEED_SIZE", 50)
|
||||||
|
|
||||||
|
|
||||||
class LatestArticlesFeed(Feed):
|
class LatestArticlesFeed(Feed):
|
||||||
feed_type = Rss201rev2Feed
|
feed_type = Rss201rev2Feed
|
||||||
title = "DeBuT AI 最新文章"
|
title = "DeBuT AI 最新文章"
|
||||||
@ -12,7 +28,7 @@ class LatestArticlesFeed(Feed):
|
|||||||
description = "DeBuT AI 最新文章 RSS feed"
|
description = "DeBuT AI 最新文章 RSS feed"
|
||||||
|
|
||||||
def items(self):
|
def items(self):
|
||||||
return ArticlePage.objects.live().order_by("-date", "-id")[:20]
|
return ArticlePage.objects.live().order_by("-date", "-id")[:ARTICLE_FEED_SIZE]
|
||||||
|
|
||||||
def item_title(self, item):
|
def item_title(self, item):
|
||||||
return item.title
|
return item.title
|
||||||
|
|||||||
@ -141,23 +141,27 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin: 40px 0 20px;
|
margin: 0;
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 15px;
|
||||||
|
letter-spacing: 0.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-size-label {
|
.page-size-label {
|
||||||
color: #0e1b4266;
|
color: #0e1b42;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-size-option {
|
.page-size-option {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
min-width: 40px;
|
min-width: 37px;
|
||||||
height: 32px;
|
height: 24px;
|
||||||
border: 1px solid #0e1b42;
|
border: 1px solid #0e1b42;
|
||||||
border-radius: 4px;
|
|
||||||
color: #0e1b42;
|
color: #0e1b42;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-size-option.is-current {
|
.page-size-option.is-current {
|
||||||
|
|||||||
@ -11,6 +11,21 @@
|
|||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.category-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-toolbar .category-title {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-toolbar .page-size-selector {
|
||||||
|
margin: 0 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
.subcategory-title {
|
.subcategory-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -38,6 +53,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
|
.category-toolbar {
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-toolbar .page-size-selector {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.subcategory-title::after {
|
.subcategory-title::after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
innovedus_cms/home/static/img/default_cover_1.jpg
Normal file
|
After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 247 KiB |
BIN
innovedus_cms/home/static/img/default_cover_2.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 212 KiB |
BIN
innovedus_cms/home/static/img/default_cover_3.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 150 KiB |
@ -27,8 +27,11 @@
|
|||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="site-hero-band full-bleed">
|
<div class="site-hero-band full-bleed">
|
||||||
<div class="site-container">
|
<div class="site-container category-toolbar">
|
||||||
<div class="block-title category-title"><span>{{ self.title}}</span></div>
|
<div class="block-title category-title"><span>{{ self.title}}</span></div>
|
||||||
|
{% if not page.has_subcategories %}
|
||||||
|
{% include "home/includes/page_size_selector.html" with category=category_sections.0 %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if page.has_subcategories %}
|
{% if page.has_subcategories %}
|
||||||
|
|||||||
@ -5,8 +5,9 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="site-hero-band full-bleed">
|
<div class="site-hero-band full-bleed">
|
||||||
<div class="site-container">
|
<div class="site-container category-toolbar">
|
||||||
<div class="block-title category-title"><span>#{{ tag.name }}</span></div>
|
<div class="block-title category-title"><span>#{{ tag.name }}</span></div>
|
||||||
|
{% include "home/includes/page_size_selector.html" with category=category_sections.0 %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -6,19 +6,6 @@
|
|||||||
<div class="page-article-list">
|
<div class="page-article-list">
|
||||||
{% include "home/includes/article_list.html" with items=category.items show_hero=show_hero empty_message=empty_message %}
|
{% include "home/includes/article_list.html" with items=category.items show_hero=show_hero empty_message=empty_message %}
|
||||||
|
|
||||||
{% if category.pagination.page_size_options %}
|
|
||||||
<div class="page-size-selector" aria-label="每頁文章數">
|
|
||||||
<span class="page-size-label">每頁</span>
|
|
||||||
{% for option in category.pagination.page_size_options %}
|
|
||||||
{% if option.is_current %}
|
|
||||||
<span class="page-size-option is-current">{{ option.value }}</span>
|
|
||||||
{% else %}
|
|
||||||
<a class="page-size-option" href="{{ option.url }}">{{ option.value }}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if category.items.paginator.num_pages > 1 %}
|
{% if category.items.paginator.num_pages > 1 %}
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
{% if category.items.has_previous %}
|
{% if category.items.has_previous %}
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
{% if category.pagination.page_size_options %}
|
||||||
|
<div class="page-size-selector" aria-label="每頁文章數">
|
||||||
|
<span class="page-size-label">每頁顯示</span>
|
||||||
|
{% for option in category.pagination.page_size_options %}
|
||||||
|
{% if option.is_current %}
|
||||||
|
<span class="page-size-option is-current">{{ option.value }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="page-size-option">
|
||||||
|
<a href="{{ option.url }}">{{ option.value }}</a>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
@ -9,8 +9,8 @@ register = template.Library()
|
|||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def random_default_cover():
|
def random_default_cover():
|
||||||
choices = (
|
choices = (
|
||||||
"img/default_cover_1.png",
|
"img/default_cover_1.jpg",
|
||||||
"img/default_cover_2.png",
|
"img/default_cover_2.jpg",
|
||||||
"img/default_cover_3.png",
|
"img/default_cover_3.jpg",
|
||||||
)
|
)
|
||||||
return static(random.choice(choices))
|
return static(random.choice(choices))
|
||||||
|
|||||||
@ -1,7 +1,19 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.templatetags.static import static
|
||||||
|
|
||||||
|
|
||||||
def ga4(request):
|
def ga4(request):
|
||||||
return {
|
return {
|
||||||
"ga4_measurement_id": getattr(settings, "GA4_MEASUREMENT_ID", ""),
|
"ga4_measurement_id": getattr(settings, "GA4_MEASUREMENT_ID", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def default_og_image(request):
|
||||||
|
return {
|
||||||
|
"default_og_image": {
|
||||||
|
"url": request.build_absolute_uri(static("img/og_default.jpg")),
|
||||||
|
"width": 528,
|
||||||
|
"height": 337,
|
||||||
|
"alt": "DeBuT AI",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@ -177,6 +177,7 @@ TEMPLATES = [
|
|||||||
"wagtail.contrib.settings.context_processors.settings",
|
"wagtail.contrib.settings.context_processors.settings",
|
||||||
"home.context_processors.navigation_pages",
|
"home.context_processors.navigation_pages",
|
||||||
"mysite.context_processors.ga4",
|
"mysite.context_processors.ga4",
|
||||||
|
"mysite.context_processors.default_og_image",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -321,6 +321,21 @@ a {
|
|||||||
color: #0e1b42;
|
color: #0e1b42;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.template-darkbackground .page-size-label {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-darkbackground .page-size-option {
|
||||||
|
border-color: #ffffffb3;
|
||||||
|
color: #ffffffb3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-darkbackground .page-size-option.is-current {
|
||||||
|
background-color: #ffffffb3;
|
||||||
|
background-clip: padding-box;
|
||||||
|
color: #0e1b42;
|
||||||
|
}
|
||||||
|
|
||||||
.template-darkbackground .site-hero-band .news-title {
|
.template-darkbackground .site-hero-band .news-title {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,12 @@
|
|||||||
{% if page.search_description %}
|
{% if page.search_description %}
|
||||||
<meta name="description" content="{{ page.search_description }}" />
|
<meta name="description" content="{{ page.search_description }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if og_image %}
|
{% firstof og_image default_og_image as resolved_og_image %}
|
||||||
<meta property="og:image" content="{{ og_image.url }}" />
|
{% if resolved_og_image %}
|
||||||
<meta property="og:image:width" content="{{ og_image.width }}" />
|
<meta property="og:image" content="{{ resolved_og_image.url }}" />
|
||||||
<meta property="og:image:height" content="{{ og_image.height }}" />
|
<meta property="og:image:width" content="{{ resolved_og_image.width }}" />
|
||||||
<meta property="og:image:alt" content="{{ og_image.alt }}" />
|
<meta property="og:image:height" content="{{ resolved_og_image.height }}" />
|
||||||
|
<meta property="og:image:alt" content="{{ resolved_og_image.alt }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="alternate" type="application/rss+xml" title="DeBuT AI 最新文章 RSS" href="{% url 'article_feed' %}">
|
<link rel="alternate" type="application/rss+xml" title="DeBuT AI 最新文章 RSS" href="{% url 'article_feed' %}">
|
||||||
|
|||||||
@ -14,8 +14,11 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
{% if search_query %}
|
{% if search_query %}
|
||||||
<div class="site-hero-band full-bleed">
|
<div class="site-hero-band full-bleed">
|
||||||
<div class="site-container">
|
<div class="site-container category-toolbar">
|
||||||
<div class="block-title category-title"><span>{{ search_query }}</span></div>
|
<div class="block-title category-title"><span>{{ search_query }}</span></div>
|
||||||
|
{% if results_count %}
|
||||||
|
{% include "home/includes/page_size_selector.html" with category=category_sections.0 %}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||