Skip to content

Commit 03fb450

Browse files
committed
refactor: extract page layouts into dedicated theme components
Delegate catch-all page template to blog-layout, root-layout, and page-layout components based on content type. Add frontmatter `layout` field for per-page override with content type as fallback.
1 parent 120e8fa commit 03fb450

6 files changed

Lines changed: 96 additions & 120 deletions

File tree

packages/markopress/CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Changelog
22

3+
## [Unreleased]
4+
5+
### ♻️ Refactoring
6+
7+
- extract page layouts into dedicated components: `blog-layout`, `root-layout`, `page-layout`
8+
- delegate catch-all page template to layout components based on content type
9+
- add layout resolution via frontmatter `layout` field with content type fallback
10+
11+
312
## [0.0.21] - 2026-05-17
413

514
### 🐛 Bug Fixes
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<div class="content content-${$global.contentTypeClass}">
2+
<theme-body-top/>
3+
<div class="content-layout">
4+
<div class="content-body">
5+
<h1>${$global.title}</h1>
6+
<if=$global.description>
7+
<p class="description">${$global.description}</p>
8+
</if>
9+
<if=$global.date>
10+
<p class="meta">Published: ${$global.date}</p>
11+
</if>
12+
<if=$global.author>
13+
<p class="meta">By ${$global.author}</p>
14+
</if>
15+
<if=$global.tags>
16+
<p class="meta">
17+
<for|tag| of=$global.tags>
18+
<span class="tag">${tag}</span>
19+
</for>
20+
</p>
21+
</if>
22+
<hr>
23+
<${$global.contentComponent || {}}>
24+
<div>No content</div>
25+
</${$global.contentComponent || {}}>
26+
</div>
27+
<if=$global.toc>
28+
<toc headers=$global.toc/>
29+
</if>
30+
</div>
31+
<theme-body-bottom/>
32+
</div>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<div class="content content-${$global.contentTypeClass}">
2+
<theme-body-top/>
3+
<div class="content-layout">
4+
<div class="content-body">
5+
<h1>${$global.title}</h1>
6+
<if=$global.description>
7+
<p class="description">${$global.description}</p>
8+
</if>
9+
<hr>
10+
<${$global.contentComponent || {}}>
11+
<div>No content</div>
12+
</${$global.contentComponent || {}}>
13+
</div>
14+
<if=$global.toc>
15+
<toc headers=$global.toc/>
16+
</if>
17+
</div>
18+
<theme-body-bottom/>
19+
</div>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<div class="content content-${$global.contentTypeClass}">
2+
<theme-body-top/>
3+
<${$global.contentComponent || {}}>
4+
<div>No content</div>
5+
</${$global.contentComponent || {}}>
6+
<if=$global.registry?.root?.length>
7+
<section class="recent-posts">
8+
<h2>Recent Posts</h2>
9+
<ul>
10+
<for|post| of=$global.registry.root
11+
.filter(post => post.metadata.date)
12+
.sort((a, b) => new Date(b.metadata.date) - new Date(a.metadata.date))
13+
.slice(0, 3)>
14+
<li>
15+
<a href=post.urlPath>${post.metadata.title || post.urlPath}</a>
16+
<small>${new Date(post.metadata.date).toLocaleDateString()}</small>
17+
</li>
18+
</for>
19+
</ul>
20+
</section>
21+
</if>
22+
<theme-body-bottom/>
23+
</div>

packages/markopress/templates/catch-all-handler.js.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,8 @@ export async function GET(context, next) {
177177
if (frontmatter.tags) {
178178
context.tags = frontmatter.tags;
179179
}
180+
181+
// Layout resolution
182+
context.layout = frontmatter.layout || contentType || 'page';
183+
context.contentTypeClass = '{{CONTENT_TYPE_CLASS}}';
180184
}
Lines changed: 9 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,9 @@
1-
<div class="content {{CONTENT_TYPE_CLASS}}">
2-
<theme-body-top/>
3-
<div class="content-layout">
4-
<div class="content-body">
5-
<h1>${$global.title}</h1>
6-
<if=$global.description>
7-
<p class="description">${$global.description}</p>
8-
</if>
9-
<if=$global.date>
10-
<p class="meta">Published: ${$global.date}</p>
11-
</if>
12-
<if=$global.author>
13-
<p class="meta">By ${$global.author}</p>
14-
</if>
15-
<if=$global.tags>
16-
<p class="meta">
17-
<for|tag| of=$global.tags>
18-
<span class="tag">${tag}</span>
19-
</for>
20-
</p>
21-
</if>
22-
<hr>
23-
<${$global.contentComponent || {}}>
24-
<div>No content</div>
25-
</${$global.contentComponent || {}}>
26-
<if=$global.registry?.blog?.length>
27-
<section class="recent-posts">
28-
<h2>Recent Posts</h2>
29-
<ul>
30-
<for|post| of=$global.registry.blog>
31-
<if=post.metadata.date>
32-
<li>
33-
<a href=post.urlPath>${post.metadata.title || post.urlPath}</a>
34-
<small>${new Date(post.metadata.date).toLocaleDateString()}</small>
35-
</li>
36-
</if>
37-
</for>
38-
</ul>
39-
</section>
40-
</if>
41-
</div>
42-
<if=$global.toc>
43-
<toc headers=$global.toc/>
44-
</if>
45-
</div>
46-
<theme-body-bottom/>
47-
</div>
48-
49-
<style>
50-
.content-layout {
51-
display: flex;
52-
gap: 32px;
53-
max-width: 1100px;
54-
margin: 0 auto;
55-
position: relative;
56-
}
57-
58-
.content-body {
59-
flex: 1;
60-
min-width: 0;
61-
max-width: 100%;
62-
}
63-
64-
.toc {
65-
position: sticky;
66-
top: 1rem;
67-
width: 200px;
68-
flex-shrink: 0;
69-
}
70-
71-
.meta {
72-
font-size: 0.875rem;
73-
color: #666;
74-
}
75-
76-
.tag {
77-
display: inline-block;
78-
background: #e5e7eb;
79-
padding: 0.125rem 0.5rem;
80-
border-radius: 4px;
81-
margin-right: 0.5rem;
82-
font-size: 0.75rem;
83-
}
84-
85-
.recent-posts {
86-
margin-top: 2rem;
87-
padding-top: 1.5rem;
88-
border-top: 1px solid #e5e7eb;
89-
}
90-
91-
.recent-posts h2 {
92-
margin-bottom: 0.75rem;
93-
}
94-
95-
.recent-posts ul {
96-
list-style: none;
97-
padding: 0;
98-
}
99-
100-
.recent-posts li {
101-
padding: 0.5rem 0;
102-
display: flex;
103-
justify-content: space-between;
104-
align-items: baseline;
105-
}
106-
107-
.recent-posts li a {
108-
color: var(--color-primary-2, #3b82f6);
109-
text-decoration: none;
110-
}
111-
112-
.recent-posts li a:hover {
113-
text-decoration: underline;
114-
}
115-
116-
.recent-posts small {
117-
color: #6b7280;
118-
font-size: 0.8rem;
119-
}
120-
</style>
1+
<if=$global.layout === 'blog'>
2+
<blog-layout/>
3+
</if>
4+
<else if=$global.layout === 'root'>
5+
<root-layout/>
6+
</else>
7+
<else>
8+
<page-layout/>
9+
</else>

0 commit comments

Comments
 (0)