Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7113e5b1f7 |
@ -14,3 +14,26 @@ def random_default_cover():
|
|||||||
"img/default_cover_3.jpg",
|
"img/default_cover_3.jpg",
|
||||||
)
|
)
|
||||||
return static(random.choice(choices))
|
return static(random.choice(choices))
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag(takes_context=True)
|
||||||
|
def idle_recommendations(context, limit=4):
|
||||||
|
from home.models import ArticlePage
|
||||||
|
|
||||||
|
current_page = context.get("page")
|
||||||
|
exclude_ids = []
|
||||||
|
current_id = getattr(current_page, "id", None)
|
||||||
|
if current_id:
|
||||||
|
exclude_ids.append(current_id)
|
||||||
|
|
||||||
|
base_qs = ArticlePage.objects.live().filter(not_news=False).exclude(id__in=exclude_ids)
|
||||||
|
articles = list(base_qs.filter(trending=True).order_by("-date", "-id")[:limit])
|
||||||
|
if len(articles) < limit:
|
||||||
|
used_ids = [article.id for article in articles]
|
||||||
|
articles.extend(
|
||||||
|
list(
|
||||||
|
base_qs.exclude(id__in=used_ids)
|
||||||
|
.order_by("-date", "-id")[: limit - len(articles)]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return articles
|
||||||
|
|||||||
315
innovedus_cms/mysite/static/css/idle_modal.css
Normal file
315
innovedus_cms/mysite/static/css/idle_modal.css
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
.idle-modal[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal,
|
||||||
|
.idle-modal * {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 2100;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__backdrop {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(14, 27, 66, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__dialog {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 1024px;
|
||||||
|
min-height: 618px;
|
||||||
|
max-width: 100vw;
|
||||||
|
overflow: visible;
|
||||||
|
padding: 82px 92px 48px 76px;
|
||||||
|
background: #0e1b42;
|
||||||
|
border: 1pt solid #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__close {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
right: 18px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 30px;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__title {
|
||||||
|
margin: 0;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: "Inter", "Noto Sans JP", sans-serif;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 29px;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__cup {
|
||||||
|
display: block;
|
||||||
|
width: 88px;
|
||||||
|
height: 98px;
|
||||||
|
margin: 23px auto 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__section-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__section-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex: 0 0 197px;
|
||||||
|
width: 197px;
|
||||||
|
height: 60px;
|
||||||
|
padding-left: 21px;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #0e1b42;
|
||||||
|
font-family: "Inter", "Noto Sans JP", sans-serif;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 60px;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__rule {
|
||||||
|
display: block;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
height: 1px;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 194px);
|
||||||
|
gap: 0 26px;
|
||||||
|
margin-top: 31px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__card {
|
||||||
|
width: 194px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__card-link {
|
||||||
|
display: block;
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__thumb {
|
||||||
|
display: block;
|
||||||
|
width: 194px;
|
||||||
|
height: 133px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__thumb img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__article-title {
|
||||||
|
display: -webkit-box;
|
||||||
|
margin-top: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: "Inter", "Noto Sans JP", sans-serif;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 32px;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px) and (max-width: 1023px) {
|
||||||
|
.idle-modal {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__dialog {
|
||||||
|
width: 768px;
|
||||||
|
min-height: 0;
|
||||||
|
max-width: 100vw;
|
||||||
|
padding: 56px 48px 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__grid {
|
||||||
|
grid-template-columns: repeat(4, 145px);
|
||||||
|
gap: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__card {
|
||||||
|
width: 145px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__thumb {
|
||||||
|
width: 139px;
|
||||||
|
height: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__article-title {
|
||||||
|
margin-top: 12px;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 575px) and (max-width: 767px) {
|
||||||
|
.idle-modal {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__dialog {
|
||||||
|
width: 575px;
|
||||||
|
min-height: 0;
|
||||||
|
max-width: 100vw;
|
||||||
|
padding: 16px 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__title {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__cup {
|
||||||
|
width: 58px;
|
||||||
|
height: 65px;
|
||||||
|
margin: 6px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__section-head {
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__section-label {
|
||||||
|
flex-basis: 197px;
|
||||||
|
width: 197px;
|
||||||
|
height: 60px;
|
||||||
|
padding-left: 21px;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 194px);
|
||||||
|
gap: 8px 16px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__card {
|
||||||
|
width: 194px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__thumb {
|
||||||
|
width: 194px;
|
||||||
|
height: 133px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__article-title {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 32px;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 574px) {
|
||||||
|
.idle-modal {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__dialog {
|
||||||
|
width: min(300px, calc(100vw - 24px));
|
||||||
|
min-height: 0;
|
||||||
|
padding: 28px 16px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__close {
|
||||||
|
top: 4px;
|
||||||
|
right: 6px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__title {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__cup {
|
||||||
|
width: 58px;
|
||||||
|
height: 65px;
|
||||||
|
margin: 12px auto 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__section-head {
|
||||||
|
height: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__section-label {
|
||||||
|
flex-basis: 139px;
|
||||||
|
width: 139px;
|
||||||
|
height: 55px;
|
||||||
|
padding-left: 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__grid {
|
||||||
|
grid-template-columns: repeat(2, 139px);
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px 10px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__thumb {
|
||||||
|
width: 139px;
|
||||||
|
height: 110px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__card {
|
||||||
|
width: 139px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.idle-modal__article-title {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
}
|
||||||
70
innovedus_cms/mysite/static/js/idle_modal.js
Normal file
70
innovedus_cms/mysite/static/js/idle_modal.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
(function () {
|
||||||
|
const modal = document.querySelector("[data-idle-modal]");
|
||||||
|
if (!modal) return;
|
||||||
|
|
||||||
|
const delay = Number.parseInt(modal.getAttribute("data-idle-delay") || "120000", 10);
|
||||||
|
const closeTargets = modal.querySelectorAll("[data-idle-close]");
|
||||||
|
const articleLinks = modal.querySelectorAll(".idle-modal__card-link");
|
||||||
|
let timer = null;
|
||||||
|
let lastActive = null;
|
||||||
|
|
||||||
|
const isOpen = () => !modal.hidden;
|
||||||
|
|
||||||
|
const clearIdleTimer = () => {
|
||||||
|
if (timer) {
|
||||||
|
window.clearTimeout(timer);
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const scheduleIdleTimer = () => {
|
||||||
|
clearIdleTimer();
|
||||||
|
if (document.hidden || isOpen()) return;
|
||||||
|
timer = window.setTimeout(() => {
|
||||||
|
lastActive = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
||||||
|
modal.hidden = false;
|
||||||
|
document.body.style.overflow = "hidden";
|
||||||
|
const closeButton = modal.querySelector(".idle-modal__close");
|
||||||
|
if (closeButton) closeButton.focus();
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
if (!isOpen()) return;
|
||||||
|
modal.hidden = true;
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
if (lastActive && typeof lastActive.focus === "function") {
|
||||||
|
lastActive.focus();
|
||||||
|
}
|
||||||
|
scheduleIdleTimer();
|
||||||
|
};
|
||||||
|
|
||||||
|
["pointermove", "keydown", "scroll", "touchstart", "click"].forEach((eventName) => {
|
||||||
|
document.addEventListener(
|
||||||
|
eventName,
|
||||||
|
() => {
|
||||||
|
if (!isOpen()) scheduleIdleTimer();
|
||||||
|
},
|
||||||
|
{ passive: true }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
closeTargets.forEach((target) => {
|
||||||
|
target.addEventListener("click", closeModal);
|
||||||
|
});
|
||||||
|
|
||||||
|
articleLinks.forEach((link) => {
|
||||||
|
link.addEventListener("click", () => {
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("keydown", (event) => {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("visibilitychange", scheduleIdleTimer);
|
||||||
|
scheduleIdleTimer();
|
||||||
|
})();
|
||||||
@ -47,6 +47,7 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="{% static 'css/footer.css' %}">
|
<link rel="stylesheet" type="text/css" href="{% static 'css/footer.css' %}">
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'css/subscribe_fab.css' %}">
|
<link rel="stylesheet" type="text/css" href="{% static 'css/subscribe_fab.css' %}">
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'css/contact_form.css' %}">
|
<link rel="stylesheet" type="text/css" href="{% static 'css/contact_form.css' %}">
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'css/idle_modal.css' %}">
|
||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
{# Override this in templates to add extra stylesheets #}
|
{# Override this in templates to add extra stylesheets #}
|
||||||
@ -67,12 +68,14 @@
|
|||||||
{% include "includes/footer.html" %}
|
{% include "includes/footer.html" %}
|
||||||
{% include "includes/contact_form.html" %}
|
{% include "includes/contact_form.html" %}
|
||||||
{% include "includes/subscribe_fab.html" %}
|
{% include "includes/subscribe_fab.html" %}
|
||||||
|
{% include "includes/idle_modal.html" %}
|
||||||
|
|
||||||
{# Global javascript #}
|
{# Global javascript #}
|
||||||
<script type="text/javascript" src="{% static 'js/mysite.js' %}"></script>
|
<script type="text/javascript" src="{% static 'js/mysite.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'js/header.js' %}"></script>
|
<script type="text/javascript" src="{% static 'js/header.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'js/contact_form.js' %}"></script>
|
<script type="text/javascript" src="{% static 'js/contact_form.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'js/subscribe_fab.js' %}"></script>
|
<script type="text/javascript" src="{% static 'js/subscribe_fab.js' %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static 'js/idle_modal.js' %}"></script>
|
||||||
{# Instagram embed script to render IG oEmbeds #}
|
{# Instagram embed script to render IG oEmbeds #}
|
||||||
<script async src="https://www.instagram.com/embed.js"></script>
|
<script async src="https://www.instagram.com/embed.js"></script>
|
||||||
|
|
||||||
|
|||||||
40
innovedus_cms/mysite/templates/includes/idle_modal.html
Normal file
40
innovedus_cms/mysite/templates/includes/idle_modal.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{% load home_tags wagtailimages_tags %}
|
||||||
|
{% idle_recommendations as idle_articles %}
|
||||||
|
{% if idle_articles %}
|
||||||
|
<div class="idle-modal" data-idle-modal data-idle-delay="120000" hidden>
|
||||||
|
<div class="idle-modal__backdrop" data-idle-close></div>
|
||||||
|
<section class="idle-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="idle-modal-title">
|
||||||
|
<button class="idle-modal__close" type="button" aria-label="關閉" data-idle-close>×</button>
|
||||||
|
<h2 class="idle-modal__title" id="idle-modal-title">你已閒置超過兩分鐘囉!</h2>
|
||||||
|
<svg class="idle-modal__cup" width="88" height="98" viewBox="489 134 89 98" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false">
|
||||||
|
<path d="M558.438 232H492.217C491.526 231.236 491.212 230.55 491.961 229.689L557.967 229.5C559.506 229.517 559.601 231.279 558.433 232H558.438Z" fill="white"/>
|
||||||
|
<path d="M559.777 168.074C565.973 165.137 572.104 166.218 575.121 172.733C578.074 179.107 577.291 187.35 574.548 193.66C570.626 202.673 562.079 208.625 552.675 210.87L550.353 224.777L549.742 225.697L499.539 225.633L499.13 224.608L489 163.05C489.164 162.378 489.724 162.109 490.391 162.135L559.302 162.14C561.877 161.992 559.399 167.686 559.777 168.074ZM557.671 164.63H491.835L501.873 223.399L547.891 223.365L557.671 164.63ZM553.081 208.076C562.897 205.419 571.055 198.582 573.582 188.483C575.3 181.61 574.512 167.249 564.17 169.309C563.104 169.522 559.586 170.843 559.184 171.787L553.081 208.076Z" fill="white"/>
|
||||||
|
<path d="M522.507 159.223C521.867 158.55 522.417 155.94 522.747 155.063C524.125 151.394 527.807 150.624 527.221 145.8C526.884 143.015 524.143 141.479 522.998 139.114C522.392 137.863 521.325 134.003 523.509 134C525.035 134 524.713 135.915 525.04 137.073C526.14 140.957 530.233 141.607 529.927 147.321C529.676 152.028 525.843 153.232 525.002 156.556C524.828 157.239 524.854 158.435 524.657 158.891C524.34 159.617 523.051 159.798 522.507 159.225V159.223Z" fill="white"/>
|
||||||
|
<path d="M503.372 159.22C502.605 158.448 503.216 156.571 503.696 155.728C504.87 153.672 508.598 152.649 508.058 150.034C507.708 148.328 504.21 147.014 503.361 144.779C502.939 143.672 502.633 141.586 504.364 141.65C505.916 141.706 505.391 143.342 506.189 144.439C507.736 146.562 510.901 147.07 510.786 150.747C510.674 154.357 507.677 154.687 506.187 156.689C505.588 157.492 505.742 158.668 505.241 159.187C504.739 159.706 503.86 159.711 503.369 159.22H503.372Z" fill="white"/>
|
||||||
|
<path d="M542.309 141.699C544.148 141.328 543.705 143.294 544.378 144.335C545.758 146.47 549.077 146.853 549.075 150.563C549.069 154.795 544.835 155.102 544.02 157.582C543.764 158.356 543.981 159.571 542.649 159.571C541.317 159.571 541.289 158.257 541.422 157.28C541.882 153.895 546.551 153.245 546.392 150.369C546.285 148.382 542.562 147.094 541.691 144.918C541.302 143.946 540.969 141.97 542.309 141.699Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
<div class="idle-modal__section-head">
|
||||||
|
<span class="idle-modal__section-label">專屬推薦</span>
|
||||||
|
<span class="idle-modal__rule" aria-hidden="true"></span>
|
||||||
|
</div>
|
||||||
|
<div class="idle-modal__grid">
|
||||||
|
{% for article in idle_articles %}
|
||||||
|
<article class="idle-modal__card">
|
||||||
|
<a class="idle-modal__card-link" href="{{ article.url }}">
|
||||||
|
<span class="idle-modal__thumb">
|
||||||
|
{% if article.cover_image %}
|
||||||
|
{% image article.cover_image max-194x133 as cover %}
|
||||||
|
<img src="{{ cover.url }}" alt="{{ article.title }}" width="194" height="133">
|
||||||
|
{% else %}
|
||||||
|
{% random_default_cover as default_cover %}
|
||||||
|
<img src="{{ default_cover }}" alt="{{ article.title }}" width="194" height="133">
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
<span class="idle-modal__article-title">{{ article.title }}</span>
|
||||||
|
</a>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
Loading…
x
Reference in New Issue
Block a user