feat(footer): Add footer component with responsive design and social media links

This commit is contained in:
Warren Chen 2026-03-06 14:26:19 +09:00
parent 9b3673831a
commit 8a0621d1ce
4 changed files with 344 additions and 232 deletions

View File

@ -0,0 +1,261 @@
.site-footer {
background: #0e1b42;
color: #ffffff;
padding: 28px 0 20px;
font-size: 14px;
}
.footer-shell {
display: flex;
flex-direction: column;
align-items: center;
}
.footer-ad-slot {
width: 100%;
}
.footer-separator {
width: 100%;
max-width: 790px;
height: 1px;
background: #ffffff4d;
margin: 0 auto 40px;
}
.footer-main {
width: 100%;
max-width: 790px;
display: grid;
grid-template-columns: 220px 220px 180px;
grid-template-areas:
"b1 b2 b3"
"b1 b2 b4";
column-gap: 40px;
row-gap: 20px;
align-items: start;
}
.footer-col--brand {
grid-area: b1;
min-width: 0;
}
.footer-brand-content img {
max-width: 100%;
height: auto;
margin-bottom: 12px;
}
.footer-brand-content p {
margin: 0 0 8px;
font-size: 12px;
line-height: 1.75;
}
.footer-col--menu {
grid-area: b2;
min-width: 0;
}
.footer-menu-list {
margin: 0;
padding: 0;
list-style: none;
column-count: 2;
column-gap: 40px;
}
.footer-menu-list li {
break-inside: avoid;
margin: 0 0 14px;
}
.footer-menu-list a {
color: #ffffff;
text-decoration: none;
line-height: 1.35;
}
.footer-menu-list a:hover {
text-decoration: underline;
}
.footer-fixed-links{
grid-area: b3;
width: 100%;
}
.footer-fixed-links ul{
margin: 0;
padding: 0;
list-style: none;
display: flex;
justify-content: space-between;
}
.footer-fixed-links a {
font-size: 10px;
line-height: 1.35;
}
.footer-fixed-links a:hover {
text-decoration: underline;
}
.footer-socials {
grid-area: b4;
width: 100%;
display: flex;
justify-content: space-between;
}
.footer-socials .icon {
width: 25px;
height: 25px;
--fill-0: #ffffff;
}
.footer-socials .icon .icon-cutout {
fill: #0e1b42;
}
.footer-powered {
margin-top: 24px;
text-align: center;
font-size: 12px;
font-weight: 100;
line-height: 1.35;
}
@media (min-width: 1024px) {
.footer-fixed-links,
.footer-socials {
align-self: end;
}
}
@media (min-width: 768px) and (max-width: 1023px) {
.footer-separator {
max-width: 616px;
}
.footer-main {
max-width: 616px;
display: grid;
grid-template-columns: 220px 150px 1fr;
grid-template-areas:
"b1 b2 b2"
"b1 b4 b3";
gap: 32px;
}
.footer-col--right:nth-child(3) {
flex-direction: row;
align-items: flex-start;
}
.footer-menu-list {
column-count: 3;
}
}
@media (max-width: 767px) {
.site-footer {
padding: 24px 0 16px;
}
.site-footer .site-container {
max-width: 494px;
}
.footer-separator {
max-width: 494px;
}
.footer-main {
max-width: 494px;
display: grid;
grid-template-columns: 220px 150px 1fr;
grid-template-areas:
"b1 b2 b3"
"b1 b4 .";
gap: 20px;
}
.footer-menu-list {
column-gap: 0px;
}
.footer-menu-list li {
margin: 0 0 6px;
}
.footer-col--right {
grid-column: auto;
align-items: flex-start;
gap: 20px;
}
.footer-fixed-links {
flex-wrap: wrap;
gap: 18px;
}
.footer-fixed-links ul {
display: block;
}
.footer-fixed-links ul li {
margin: 0 0 4px;
}
}
@media (max-width: 574px) {
.footer-separator {
max-width: 289px;
}
.footer-main {
max-width: 220px;
margin-inline: auto;
justify-content: center;
grid-template-columns: 1fr;
grid-template-areas:
"b2"
"b1"
"b4"
"b3";
gap: 20px;
}
.footer-col--menu,
.footer-col--right,
.footer-fixed-links,
.footer-socials {
width: 100%;
}
.footer-menu-list {
text-align: center;
}
.footer-fixed-links ul {
display: flex;
flex-wrap: wrap;
gap: 12px 18px;
}
.footer-menu-list a {
font-size: 16px;
}
.footer-fixed-links a {
font-size: 12px;
}
.footer-socials .icon {
width: 35px;
height: 35px;
}
}

View File

@ -66,7 +66,7 @@ a {
.main-menu { .main-menu {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 24px; gap: 18px;
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -276,7 +276,7 @@ a {
border: 0; border: 0;
background: transparent; background: transparent;
outline: none; outline: none;
width: 181px; width: 153px;
} }
.template-darkbackground .header-search input[type="search"] { .template-darkbackground .header-search input[type="search"] {
@ -287,129 +287,6 @@ a {
color: #ffffff88; color: #ffffff88;
} }
footer {
background: #0e1b42;
color: #ffffff;
padding: 24px 0;
font-size: 14px;
}
.footer-inner {
display: flex;
justify-content: center;
gap: 48px;
align-items: flex-start;
text-align: left;
}
footer .company-info {
max-width: 300px;
margin: 0;
padding: 0 16px;
}
footer .copyright img {
margin: 10px 0;
width: 265px;
height: 37px;
}
footer .copyright p {
font-size: 10px;
text-align: left;
margin: 0;
}
.footer-socials {
display: flex;
gap: 12px;
margin: 16px 0;
flex-wrap: wrap;
}
.footer-socials .icon {
width: 32px;
height: 32px;
--fill-0: #ffffff;
}
.footer-socials .icon circle {
fill: #ffffff;
fill-opacity: 0.85;
}
.footer-socials .icon .icon-cutout {
fill: #0e1b42;
}
.newsletter-subscribe-form {
margin-top: 16px;
}
.newsletter-subscribe-form label {
display: block;
margin-bottom: 8px;
font-size: 12px;
font-weight: 700;
}
.newsletter-subscribe-controls {
display: flex;
align-items: center;
gap: 8px;
}
.newsletter-subscribe-controls input[type="email"] {
width: 180px;
max-width: 100%;
padding: 8px;
border: 1px solid #ffffff66;
border-radius: 4px;
background: #ffffff;
color: #0e1b42;
}
.newsletter-subscribe-controls button {
border: 1px solid #ffffff;
border-radius: 4px;
background: transparent;
color: #ffffff;
padding: 8px 12px;
cursor: pointer;
}
.newsletter-subscribe-controls button:hover {
background: #ffffff;
color: #0e1b42;
}
footer .footer-links {
padding: 0 16px;
}
footer .footer-links li {
list-style-type: none;
}
footer .footer-links a {
font-size: 14px;
}
footer .footer-divider {
align-self: stretch;
display: flex;
align-items: center;
padding: 0 8px;
width: 1px;
border-left: 1px solid #ffffff;
}
footer .footer-sections {
display: flex;
gap: 32px;
flex-wrap: wrap;
}
.block-title { .block-title {
display: inline-block; display: inline-block;
width: 197px; width: 197px;
@ -470,39 +347,6 @@ footer .footer-sections {
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.footer-inner {
flex-direction: column;
align-items: center;
text-align: center;
}
footer .company-info,
footer .footer-links {
max-width: 100%;
}
.footer-socials {
justify-content: center;
}
.newsletter-subscribe-controls {
justify-content: center;
}
footer .footer-sections {
justify-content: center;
}
footer .footer-divider {
width: 100%;
padding: 12px 0;
border-left: 0;
border-top: 1px solid #ffffff;
}
footer .copyright p {
text-align: center;
}
} }
@media (min-width: 575px) and (max-width: 767px) { @media (min-width: 575px) and (max-width: 767px) {

View File

@ -34,6 +34,7 @@
{# Global stylesheets #} {# Global stylesheets #}
<link rel="stylesheet" type="text/css" href="{% static 'css/mysite.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'css/mysite.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/footer.css' %}">
{% block extra_css %} {% block extra_css %}
{# Override this in templates to add extra stylesheets #} {# Override this in templates to add extra stylesheets #}

View File

@ -1,30 +1,63 @@
{% load navigation_tags %} {% load navigation_tags %}
<footer> <footer class="site-footer">
<div class="site-container footer-inner"> <div class="site-container footer-shell">
<div class="company-info"> <div class="footer-ad-slot" aria-hidden="true"></div>
<div class="copyright"> <div class="footer-separator" aria-hidden="true"></div>
<div class="footer-main">
<div class="footer-col footer-col--brand">
<div class="footer-brand-content">
{% get_footer_text %} {% get_footer_text %}
</div> </div>
</div>
<nav class="footer-col footer-col--menu" aria-label="Footer main menu">
<ul class="footer-menu-list">
{% if nav_latest_page %}
<li><a href="{{ nav_latest_page.url }}">{{ nav_latest_page.title }}</a></li>
{% else %}
<li><a href="#">最新文章</a></li>
{% endif %}
{% if page %}
{% with site_root=page.get_site.root_page %}
{% for menu_page in site_root.get_children.live.in_menu %}
<li><a href="{{ menu_page.url }}">{{ menu_page.title }}</a></li>
{% endfor %}
{% endwith %}
{% endif %}
</ul>
</nav>
<!-- <div class="footer-col footer-col--right"> -->
<div class="footer-fixed-links">
<ul>
<li><a href="{% url 'newsletter_subscribe' %}">訂閱電子報</a></li>
<li><a href="#">合作提案</a></li>
<li><a href="#">聯絡我們</a></li>
</ul>
</div>
{% with social_links=settings.base.SocialMediaSettings.links %} {% with social_links=settings.base.SocialMediaSettings.links %}
{% if social_links %} {% if social_links %}
<div class="footer-socials" aria-label="social icons"> <div class="footer-socials" aria-label="social icons">
{% for item in social_links %} {% for item in social_links %}
<a href="{{ item.value.url }}" target="_blank" aria-label="{{ item.value.platform }}"> <a href="{{ item.value.url }}" target="_blank" rel="noopener noreferrer" aria-label="{{ item.value.platform }}">
{% if item.value.platform|lower == "facebook" %} {% if item.value.platform|lower == "facebook" %}
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="facebook" role="img"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="facebook" role="img">
<path d="M16.59 0C7.43 0 0 7.43 0 16.59C0 25.75 7.43 33.18 16.59 33.18C25.75 33.18 33.18 25.75 33.18 16.59C33.18 7.43 25.75 0 16.59 0ZM23.12 8.37H21.18C19.27 8.37 18.67 9.56 18.67 10.78V13.67H22.94L22.26 18.12H18.67V28.89H13.85V18.12H9.94V13.67H13.85V10.28C13.85 6.42 16.15 4.29 19.67 4.29C21.36 4.29 23.12 4.59 23.12 4.59V8.38V8.37Z" fill="var(--fill-0, #0E1B42)" id="Vector"/> <path d="M16.59 0C7.43 0 0 7.43 0 16.59C0 25.75 7.43 33.18 16.59 33.18C25.75 33.18 33.18 25.75 33.18 16.59C33.18 7.43 25.75 0 16.59 0ZM23.12 8.37H21.18C19.27 8.37 18.67 9.56 18.67 10.78V13.67H22.94L22.26 18.12H18.67V28.89H13.85V18.12H9.94V13.67H13.85V10.28C13.85 6.42 16.15 4.29 19.67 4.29C21.36 4.29 23.12 4.59 23.12 4.59V8.38V8.37Z" fill="var(--fill-0, #0E1B42)"/>
</svg> </svg>
{% elif item.value.platform|lower == "instagram" %} {% elif item.value.platform|lower == "instagram" %}
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="instagram" role="img"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="instagram" role="img">
<path d="M16.67 13.42C14.92 13.42 13.5 14.84 13.5 16.59C13.5 18.34 14.92 19.76 16.67 19.76C18.42 19.76 19.84 18.34 19.84 16.59C19.84 14.84 18.42 13.42 16.67 13.42Z" fill="var(--fill-0, #0E1B42)" id="Vector"/> <path d="M16.67 13.42C14.92 13.42 13.5 14.84 13.5 16.59C13.5 18.34 14.92 19.76 16.67 19.76C18.42 19.76 19.84 18.34 19.84 16.59C19.84 14.84 18.42 13.42 16.67 13.42Z" fill="var(--fill-0, #0E1B42)"/>
<path d="M20.6 8.42H12.57C10.28 8.42 8.42 10.28 8.42 12.57V20.6C8.42 22.89 10.28 24.75 12.57 24.75H20.6C22.89 24.75 24.75 22.89 24.75 20.6V12.57C24.75 10.28 22.89 8.42 20.6 8.42ZM16.67 21.54C13.94 21.54 11.72 19.32 11.72 16.59C11.72 13.86 13.94 11.64 16.67 11.64C19.4 11.64 21.62 13.86 21.62 16.59C21.62 19.32 19.4 21.54 16.67 21.54ZM21.91 12.48C21.26 12.48 20.73 11.95 20.73 11.3C20.73 10.65 21.26 10.12 21.91 10.12C22.56 10.12 23.09 10.65 23.09 11.3C23.09 11.95 22.56 12.48 21.91 12.48Z" fill="var(--fill-0, #0E1B42)" id="Vector_2"/> <path d="M20.6 8.42H12.57C10.28 8.42 8.42 10.28 8.42 12.57V20.6C8.42 22.89 10.28 24.75 12.57 24.75H20.6C22.89 24.75 24.75 22.89 24.75 20.6V12.57C24.75 10.28 22.89 8.42 20.6 8.42ZM16.67 21.54C13.94 21.54 11.72 19.32 11.72 16.59C11.72 13.86 13.94 11.64 16.67 11.64C19.4 11.64 21.62 13.86 21.62 16.59C21.62 19.32 19.4 21.54 16.67 21.54ZM21.91 12.48C21.26 12.48 20.73 11.95 20.73 11.3C20.73 10.65 21.26 10.12 21.91 10.12C22.56 10.12 23.09 10.65 23.09 11.3C23.09 11.95 22.56 12.48 21.91 12.48Z" fill="var(--fill-0, #0E1B42)"/>
<path d="M16.59 0C7.43 0 0 7.43 0 16.59C0 25.75 7.43 33.18 16.59 33.18C25.75 33.18 33.18 25.75 33.18 16.59C33.18 7.43 25.75 0 16.59 0ZM26.64 20.6C26.64 23.93 23.93 26.64 20.6 26.64H12.57C9.24 26.64 6.53 23.93 6.53 20.6V12.57C6.53 9.24 9.24 6.53 12.57 6.53H20.6C23.93 6.53 26.64 9.24 26.64 12.57V20.6Z" fill="var(--fill-0, #0E1B42)" id="Vector_3"/> <path d="M16.59 0C7.43 0 0 7.43 0 16.59C0 25.75 7.43 33.18 16.59 33.18C25.75 33.18 33.18 25.75 33.18 16.59C33.18 7.43 25.75 0 16.59 0ZM26.64 20.6C26.64 23.93 23.93 26.64 20.6 26.64H12.57C9.24 26.64 6.53 23.93 6.53 20.6V12.57C6.53 9.24 9.24 6.53 12.57 6.53H20.6C23.93 6.53 26.64 9.24 26.64 12.57V20.6Z" fill="var(--fill-0, #0E1B42)"/>
</svg> </svg>
{% elif item.value.platform|lower == "youtube" %} {% elif item.value.platform|lower == "youtube" %}
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="youtube" role="img"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="youtube" role="img">
<path d="M20.36 16.45L15.14 13.61C14.93 13.49 14.19 13.64 14.19 13.89V19.43C14.19 19.67 14.92 19.83 15.13 19.71L20.59 17.01C20.81 16.89 20.59 16.57 20.36 16.45Z" fill="var(--fill-0, #0E1B42)" id="Vector"/> <path d="M20.36 16.45L15.14 13.61C14.93 13.49 14.19 13.64 14.19 13.89V19.43C14.19 19.67 14.92 19.83 15.13 19.71L20.59 17.01C20.81 16.89 20.59 16.57 20.36 16.45Z" fill="var(--fill-0, #0E1B42)"/>
<path d="M16.59 0C7.43 0 0 7.43 0 16.59C0 25.75 7.43 33.18 16.59 33.18C25.75 33.18 33.18 25.75 33.18 16.59C33.18 7.43 25.75 0 16.59 0ZM27.74 19.42C27.74 22.05 25.61 24.18 22.98 24.18H10.81C8.18 24.18 6.05 22.05 6.05 19.42V13.76C6.05 11.13 8.18 9 10.81 9H22.98C25.61 9 27.74 11.13 27.74 13.76V19.42Z" fill="var(--fill-0, #0E1B42)" id="Vector_2"/> <path d="M16.59 0C7.43 0 0 7.43 0 16.59C0 25.75 7.43 33.18 16.59 33.18C25.75 33.18 33.18 25.75 33.18 16.59C33.18 7.43 25.75 0 16.59 0ZM27.74 19.42C27.74 22.05 25.61 24.18 22.98 24.18H10.81C8.18 24.18 6.05 22.05 6.05 19.42V13.76C6.05 11.13 8.18 9 10.81 9H22.98C25.61 9 27.74 11.13 27.74 13.76V19.42Z" fill="var(--fill-0, #0E1B42)"/>
</svg> </svg>
{% elif item.value.platform|lower == "threads" %} {% elif item.value.platform|lower == "threads" %}
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="threads" role="img"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 33.18 33.18" aria-label="threads" role="img">
@ -49,36 +82,9 @@
</div> </div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<!-- </div> -->
<form class="newsletter-subscribe-form" method="post" action="{% url 'newsletter_subscribe' %}">
{% csrf_token %}
<label for="newsletter-email">訂閱電子報</label>
<div class="newsletter-subscribe-controls">
<input id="newsletter-email" type="email" name="email" required placeholder="輸入 Email">
<button type="submit">送出</button>
</div>
</form>
</div> </div>
<div class="footer-divider" aria-hidden="true"></div> <div class="footer-powered">power by INNOVEDUS</div>
<div class="footer-links">
{% if settings.base.NavigationSettings.footer_links %}
<div class="footer-sections">
{% for section in settings.base.NavigationSettings.footer_links %}
<div class="footer-section">
{% if section.value.title %}
<h3>{{ section.value.title }}</h3>
{% endif %}
<ul>
{% for link in section.value.links %}
<li><a href="{{ link.url }}" target="_blank">{{ link.label }}</a></li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>
{% endif %}
</div>
</div> </div>
</footer> </footer>