feat: liquid glass UI, blob background, redesign home/portfolio/about pages

- Liquid glass effect on navbar/cards with backdrop-filter invert
- Animated blob gradient background (SVG-based)
- Portfolio section: scene-dark invert, show 5 items on home
- How Work section: step flow with numbers + connecting lines
- Hero: Decision snapshot replacing problem selector
- About page: inverted background with contrast fixes
- Fix parallax JS bundling via Astro
- Fix navbar fixed positioning after liquid glass CSS
- Submenu hover fix
- Clean up removed legacy files/assets
This commit is contained in:
Kunthawat Greethong
2026-06-23 11:40:37 +07:00
parent e279119f97
commit f827afb33f
188 changed files with 4577 additions and 15483 deletions

View File

@@ -1,307 +1,53 @@
---
import Base from '../../layouts/Base.astro';
import Hero from '../../components/Hero.astro';
import PageShell from '../../components/PageShell.astro';
import { getCollection, render } from 'astro:content';
const { slug } = Astro.params;
const allPosts = await getCollection('blog');
const post = allPosts.find(p => p.id === slug);
if (!post) {
return Astro.redirect('/404');
}
export async function getStaticPaths() {
const allPosts = await getCollection('blog');
return allPosts.map(post => ({
const posts = await getCollection('blog', ({ data }) => !data.draft);
return posts.map((post) => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await render(post);
const related = allPosts
.filter(p => p.id !== post.id)
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
.slice(0, 3);
const formattedDate = post.data.date.toLocaleDateString('th-TH', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
// Surface rotation for related cards
const surfaces = ['soft', 'yellow', 'mint'] as const;
function surfaceFor(i: number) {
return surfaces[i % surfaces.length];
}
const formattedDate = new Intl.DateTimeFormat('th-TH', {
dateStyle: 'long',
}).format(post.data.pubDate);
---
<Base title={`${post.data.title} | MoreminiMore`}>
<Hero
eyebrow={post.data.category}
title={post.data.title}
lede={formattedDate}
showStats={false} />
{post.data.image && (
<section class="section section-bento article-image-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="article-image">
<img src={post.data.image} alt={post.data.title} />
</div>
<PageShell title={`${post.data.title} | MoreminiMore`} description={post.data.description}>
<article class="blog-article">
<header class="blog-article-hero scene scene-light" data-scene="light">
<div class="blog-article-heading">
<a class="text-link" href="/blog/">บทความทั้งหมด</a>
<p class="eyebrow">{post.data.category} · {formattedDate}</p>
<h1>{post.data.title}</h1>
<p>{post.data.description}</p>
</div>
</section>
)}
</header>
<section class="section section-bento article-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="bento-grid">
<div class="blog-article-shell">
<div class="blog-prose liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<Content />
</div>
</div>
</article>
<!-- Main article body — full width bento tile -->
<div class="bento-tile span-8 surface-white">
<div class="article-meta">
<span class="article-date">{formattedDate}</span>
</div>
<div class="article-body">
<Content />
</div>
</div>
<!-- Sidebar tile: about + contact stack -->
<div class="bento-tile span-4 surface-soft">
<p>ดิจิทัลเอเจนซี่ที่ช่วยให้ธุรกิจไทยเติบโตด้วยเทคโนโลยีสมัยใหม่</p>
<a href="/about" class="btn btn-outline-dark btn-sm">ดูเพิ่มเติม</a>
<div class="sidebar-divider"></div>
<span class="tile-eyebrow-sm">สนใจบริการ?</span>
<p style="margin-top: 8px;">ติดต่อเราได้เลย ปรึกษาฟรี!</p>
<div class="sidebar-actions">
<a href="/contact" class="btn btn-primary btn-sm">ติดต่อเรา</a>
<a href="tel:0809955945" class="btn btn-outline-dark btn-sm">080-995-5945</a>
</div>
</div>
</div>
<section class="final-cta">
<div class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Next step</p>
<h2>อ่านแล้วเจอโจทย์คล้ายกัน ส่งปัญหามาให้เราช่วยดูก่อนได้</h2>
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</div>
</section>
{related.length > 0 && (
<section class="section section-bento related-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal">
<span class="section-badge">บทความที่เกี่ยวข้อง</span>
<h2 class="section-title">อ่านต่อ <span class="highlight">เนื้อหาใกล้เคียง</span></h2>
</div>
<div class="bento-grid">
{related.map((r, i) => (
<a href={`/blog/${r.id}`} class="related-link">
<div class="bento-tile span-4">
<div class="related-card-body">
{r.data.image && (
<div class="related-image">
<img src={r.data.image} alt={r.data.title} loading="lazy" />
</div>
)}
<span class="related-date">
{new Date(r.data.date).toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })}
</span>
</div>
</div>
</a>
))}
</div>
</div>
</section>
)}
</Base>
<style>
.article-image-section { background: var(--color-white); padding-top: 40px; padding-bottom: 40px; }
.article-section { background: var(--color-white); }
.related-section { background: var(--color-bg-alt); }
.section-bento { position: relative; overflow: hidden; }
/* Article image (hero) */
.article-image {
width: 100%;
overflow: hidden;
border-radius: var(--radius-xl);
background: var(--color-bg-soft);
}
.article-image img {
width: 100%;
max-height: 500px;
object-fit: cover;
display: block;
}
/* Main article body */
.article-meta {
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid var(--color-gray-200);
}
.article-date {
font-size: 13px;
font-weight: 700;
color: var(--color-gray-600);
text-transform: uppercase;
letter-spacing: 1px;
}
.article-body {
font-size: 17px;
line-height: 1.8;
color: var(--color-gray-700);
}
.article-body :global(h2) {
font-family: var(--font-display);
font-size: 26px;
font-weight: 800;
color: var(--color-black);
margin: 36px 0 18px;
}
.article-body :global(h3) {
font-family: var(--font-display);
font-size: 20px;
font-weight: 800;
color: var(--color-black);
margin: 28px 0 14px;
}
.article-body :global(p) { margin-bottom: 18px; }
.article-body :global(ul), .article-body :global(ol) {
margin: 16px 0;
padding-left: 24px;
}
.article-body :global(li) { margin-bottom: 10px; }
.article-body :global(a) {
color: var(--color-primary-dark);
font-weight: 600;
}
.article-body :global(a:hover) { text-decoration: underline; }
.article-body :global(blockquote) {
border-left: 4px solid var(--color-primary);
padding-left: 20px;
margin: 28px 0;
font-style: italic;
color: var(--color-gray-700);
}
.article-body :global(img) {
border-radius: var(--radius-md);
margin: 20px 0;
max-width: 100%;
}
.article-body :global(strong) { color: var(--color-black); font-weight: 800; }
/* Sidebar (soft tile) */
.sidebar-divider {
height: 1px;
background: var(--color-gray-200);
margin: 24px 0;
}
.tile-eyebrow-sm {
font-size: 11px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 2px;
opacity: 0.7;
display: block;
}
.sidebar-actions {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 12px;
}
.btn-sm {
padding: 10px 20px;
font-size: 13px;
border-radius: var(--radius-md);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* Section header */
.section-header { text-align: center; margin-bottom: 48px; }
.section-badge {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 8px 20px;
border-radius: var(--radius-full);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: 16px;
}
.section-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 40px);
font-weight: 900;
color: var(--color-black);
}
.section-title .highlight { color: var(--color-primary-dark); }
/* Related cards */
.related-link {
display: block;
text-decoration: none;
color: inherit;
}
.related-card-body {
display: flex;
flex-direction: column;
gap: 12px;
}
.related-image {
aspect-ratio: 16/10;
overflow: hidden;
border-radius: var(--radius-md);
background: var(--color-bg-soft);
margin: -8px -8px 4px;
}
.related-image img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform 0.5s ease;
}
.related-link:hover .related-image img { transform: scale(1.06); }
.related-date {
font-size: 12px;
font-weight: 600;
opacity: 0.65;
}
@media (max-width: 640px) {
.article-body { font-size: 16px; }
}
</style>
<script>
</script>
</PageShell>