Skip to content

Commit c05ce08

Browse files
author
y-yamasaki
committed
Merge branch 'develop'
2 parents 4740f73 + 8e6cb25 commit c05ce08

26 files changed

Lines changed: 1101 additions & 1205 deletions

WebSite/assets/css/base.css

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,11 @@ html {
5959
scroll-behavior: smooth;
6060
-webkit-text-size-adjust: 100%;
6161
text-size-adjust: 100%;
62-
overflow-x: hidden; /* 横スクロール防止 */
6362
}
6463

6564
body {
6665
margin: 0;
6766
padding: 0;
68-
overflow-x: hidden; /* 横スクロール防止 */
6967
font-family: var(--font-body);
7068
line-height: 1.6;
7169
color: var(--color-text);

WebSite/assets/css/blog.css

Lines changed: 136 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,6 @@
189189
3. 記事詳細ページ
190190
========================================================================== */
191191
.post-detail {
192-
max-width: 50rem;
193-
margin: 0 auto;
194192
background: var(--color-panel);
195193
border-radius: var(--radius-lg);
196194
padding: 3rem;
@@ -202,7 +200,7 @@
202200
margin-bottom: 2.5rem;
203201
padding-bottom: 2rem;
204202
border-bottom: 1px solid var(--color-border-soft);
205-
text-align: center; /* タイトル周りを中央寄せに */
203+
text-align: center;
206204
}
207205

208206
.post-detail__meta {
@@ -501,11 +499,10 @@
501499
}
502500
.post-detail {
503501
padding: 1.5rem; /* スマホでは余白を詰める */
504-
border-radius: 0; /* 画面幅いっぱいの場合は角丸なしも一案だが、page-shellがあるので維持 */
502+
border-radius: 0;
505503
border-left: none;
506504
border-right: none;
507-
box-shadow: none; /* シンプルに */
508-
background: transparent; /* 背景を抜いて馴染ませる手もあるが、ここではpanel維持 */
505+
box-shadow: none;
509506
background: var(--color-panel);
510507
}
511508
.post-detail__title {
@@ -523,8 +520,8 @@
523520
}
524521

525522
/* ==========================================================================
526-
6. ページネーション
527-
========================================================================== */
523+
6. ページネーション
524+
========================================================================== */
528525
.pagination {
529526
display: flex;
530527
justify-content: center;
@@ -575,7 +572,6 @@
575572
/* ==========================================================================
576573
7. 記事詳細のナビゲーション
577574
========================================================================== */
578-
579575
.post-detail__nav--bottom {
580576
margin-top: 3rem;
581577
margin-bottom: 0;
@@ -607,9 +603,31 @@
607603
8. パンくずリスト
608604
========================================================================== */
609605
.breadcrumb {
610-
margin-bottom: 2rem;
606+
margin-bottom: 1.5rem;
611607
font-size: 0.9rem;
612608
color: var(--color-text-muted);
609+
white-space: nowrap; /* Prevent wrapping */
610+
overflow-x: auto; /* Allow horizontal scrolling if needed */
611+
-webkit-overflow-scrolling: touch; /* Smooth scrolling on touch devices */
612+
scrollbar-width: none; /* Hide scrollbar for Firefox */
613+
}
614+
.breadcrumb::-webkit-scrollbar {
615+
display: none; /* Hide scrollbar for Chrome, Safari */
616+
}
617+
618+
.breadcrumb__list {
619+
list-style: none;
620+
padding: 0;
621+
margin: 0;
622+
display: flex;
623+
align-items: center;
624+
}
625+
626+
.breadcrumb__item:not(:last-child)::after {
627+
content: ">";
628+
margin: 0 0.75rem;
629+
color: var(--color-text-muted);
630+
opacity: 0.5;
613631
}
614632

615633
.breadcrumb a {
@@ -623,11 +641,115 @@
623641
text-decoration: underline;
624642
}
625643

626-
.breadcrumb-separator {
627-
margin: 0 0.5rem;
644+
.breadcrumb__item[aria-current="page"] {
645+
font-weight: 600;
646+
color: var(--color-text);
647+
}
648+
649+
/* ==========================================================================
650+
9. 記事詳細レイアウト(2カラム)
651+
========================================================================== */
652+
.post-layout {
653+
display: grid;
654+
grid-template-columns: 1fr;
655+
gap: 2rem;
656+
}
657+
658+
.post-content {
659+
min-width: 0;
660+
}
661+
662+
.post-sidebar {
663+
display: none;
664+
}
665+
666+
@media (min-width: 1000px) {
667+
.post-layout {
668+
grid-template-columns: minmax(0, 1fr) 250px;
669+
gap: 1rem;
670+
}
671+
.post-sidebar {
672+
display: block;
673+
}
674+
675+
body[data-page="blog"] .main-container {
676+
max-width: 1180px;
677+
}
678+
}
679+
680+
/* ==========================================================================
681+
10. 目次 (TOC)
682+
========================================================================== */
683+
.toc-sticky-container {
684+
position: sticky;
685+
top: 6rem; /* ヘッダーの高さ + 余白 */
686+
}
687+
688+
.toc {
689+
background: var(--color-surface);
690+
border-radius: var(--radius-lg);
691+
padding: 1.5rem;
692+
border: 1px solid var(--color-border);
693+
}
694+
695+
.toc__title {
696+
font-size: 1.2rem;
697+
font-weight: 700;
698+
color: var(--color-heading);
699+
margin-top: 0;
700+
margin-bottom: 1rem;
701+
padding-bottom: 0.8rem;
702+
border-bottom: 1px solid var(--color-border-soft);
703+
}
704+
705+
.toc-list {
706+
list-style: none;
707+
padding: 0;
708+
margin: 0;
709+
max-height: calc(100vh - 12rem);
710+
overflow-y: auto;
711+
}
712+
713+
.toc-item {
714+
margin-bottom: 0.5rem;
715+
}
716+
717+
.toc-item a {
718+
color: var(--color-text-muted);
719+
text-decoration: none;
720+
font-size: 0.9rem;
721+
line-height: 1.5;
722+
transition: var(--transition-smooth);
723+
display: block;
724+
}
725+
726+
.toc-item a:hover {
727+
color: var(--color-accent);
728+
transform: translateX(4px);
729+
}
730+
731+
.toc-item--level-3 {
732+
padding-left: 1.2rem;
628733
}
629734

630-
.breadcrumb-current {
735+
.toc-item--level-3 a {
736+
font-size: 0.85rem;
737+
position: relative;
738+
}
739+
740+
.toc-item--level-3 a::before {
741+
content: "";
742+
position: absolute;
743+
left: -1rem;
744+
top: 50%;
745+
transform: translateY(-50%);
746+
width: 4px;
747+
height: 4px;
748+
border-radius: 50%;
749+
background-color: var(--color-border);
750+
}
751+
752+
.toc-item a.is-active {
753+
color: var(--color-accent);
631754
font-weight: 600;
632-
color: var(--color-text);
633755
}

WebSite/assets/data/blogList.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,31 @@
4242
"recommended": false
4343
},
4444
{
45-
"id": "blog_00013",
46-
"title": "ポートフォリオの詳細表示をモーダル化してUXを改善する",
45+
"id": "blog_00012",
46+
"title": "静的サイトにお問い合わせフォームを実装する (GAS連携)",
4747
"date": "2025-11-27T00:00:00.000Z",
4848
"category": "技術メモ",
49-
"description": "ポートフォリオサイトの作品詳細を、ページ遷移なしで閲覧できるようにモーダルウィンドウ化しました。DOMParserを使ったHTML取得や、実装時のハマりポイントについて",
49+
"description": "GitHub Pagesなどの静的サイトで、サーバーを持たずにお問い合わせフォームを実装する方法(Google Apps Script利用)をまとめました",
5050
"tags": [
51-
"javascript",
52-
"ui-ux"
51+
"gas",
52+
"javascript"
5353
],
5454
"thumbnail": "assets/img/ogp.png",
55-
"contentPath": "blog/blog_00013.html",
55+
"contentPath": "blog/blog_00012.html",
5656
"recommended": false
5757
},
5858
{
59-
"id": "blog_00012",
60-
"title": "静的サイトにお問い合わせフォームを実装する (GAS連携)",
59+
"id": "blog_00013",
60+
"title": "ポートフォリオの詳細表示をモーダル化してUXを改善する",
6161
"date": "2025-11-27T00:00:00.000Z",
6262
"category": "技術メモ",
63-
"description": "GitHub Pagesなどの静的サイトで、サーバーを持たずにお問い合わせフォームを実装する方法(Google Apps Script利用)をまとめました",
63+
"description": "ポートフォリオサイトの作品詳細を、ページ遷移なしで閲覧できるようにモーダルウィンドウ化しました。DOMParserを使ったHTML取得や、実装時のハマりポイントについて",
6464
"tags": [
65-
"gas",
66-
"javascript"
65+
"javascript",
66+
"ui-ux"
6767
],
6868
"thumbnail": "assets/img/ogp.png",
69-
"contentPath": "blog/blog_00012.html",
69+
"contentPath": "blog/blog_00013.html",
7070
"recommended": false
7171
},
7272
{

WebSite/assets/js/toc.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
document.addEventListener("DOMContentLoaded", () => {
2+
// 目次内のリンクをすべて取得
3+
const tocLinks = document.querySelectorAll(".toc a");
4+
if (tocLinks.length === 0) {
5+
return;
6+
}
7+
8+
// 目次リンクから対応する見出し要素を取得
9+
const headings = Array.from(tocLinks)
10+
.map((link) => {
11+
const href = link.getAttribute("href");
12+
if (!href || !href.startsWith("#")) return null;
13+
return document.getElementById(href.substring(1));
14+
})
15+
.filter(Boolean);
16+
17+
if (headings.length === 0) {
18+
return;
19+
}
20+
21+
// IntersectionObserverを初期化して、見出しが画面内に入ったかを監視
22+
const observer = new IntersectionObserver(
23+
(entries) => {
24+
let activeHeading = null;
25+
26+
// 画面内に表示されている見出しの中から、最も上にあるものを探す
27+
for (const entry of entries) {
28+
if (entry.isIntersecting) {
29+
if (
30+
!activeHeading ||
31+
entry.boundingClientRect.top <
32+
activeHeading.boundingClientRect.top
33+
) {
34+
activeHeading = entry.target;
35+
}
36+
}
37+
}
38+
39+
// 画面内に見出しがない場合、最後に通過した見出しをアクティブにする
40+
if (!activeHeading) {
41+
for (let i = headings.length - 1; i >= 0; i--) {
42+
if (headings[i].getBoundingClientRect().top < 0) {
43+
activeHeading = headings[i];
44+
break;
45+
}
46+
}
47+
}
48+
49+
// すべての目次リンクのアクティブ状態を更新
50+
tocLinks.forEach((link) => {
51+
const isActive =
52+
activeHeading &&
53+
link.getAttribute("href") ===
54+
`#${activeHeading.id}`;
55+
link.classList.toggle("is-active", isActive);
56+
});
57+
},
58+
{
59+
// ビューポートの上部20%から下部80%の範囲で見出しを監視
60+
rootMargin: "-20% 0px -80% 0px",
61+
threshold: 0,
62+
},
63+
);
64+
65+
// すべての見出しを監視対象に追加
66+
headings.forEach((heading) => observer.observe(heading));
67+
});

0 commit comments

Comments
 (0)