mirror of
https://github.com/kbenestad/mdcms.git
synced 2026-06-18 15:24:32 +00:00
Merge pull request #12 from kbenestad/claude/config-keys-overview-e3lj1
Claude/config keys overview e3lj1
This commit is contained in:
commit
7edc7ab339
12 changed files with 215 additions and 62 deletions
|
|
@ -122,8 +122,7 @@ sort: 100 # controls nav ordering (lower = higher)
|
||||||
section-id: blog # assigns page to a nav section
|
section-id: blog # assigns page to a nav section
|
||||||
draft: true # exclude from nav and search
|
draft: true # exclude from nav and search
|
||||||
author: Name
|
author: Name
|
||||||
date: 2025-01-01
|
created: 2025-01-01 13:00
|
||||||
datetime: 2025-01-01 13:00 # use this for posts (not `date` alone — see known limitations)
|
|
||||||
modified: 2025-01-15 09:00
|
modified: 2025-01-15 09:00
|
||||||
keywords: foo, bar
|
keywords: foo, bar
|
||||||
description: Short description for search
|
description: Short description for search
|
||||||
|
|
@ -153,13 +152,13 @@ Embed post lists in pages using fenced blocks:
|
||||||
|
|
||||||
````markdown
|
````markdown
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-datetime-reversechronological
|
posts-created-reversechronological
|
||||||
limit: 10
|
limit: 10
|
||||||
paginate: yes
|
paginate: yes
|
||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
||||||
Reliable tags (others are known-broken): `posts-datetime-chronological-byyearmonth`, `posts-datetime-reversechronological`. Use `datetime` frontmatter (format: `YYYY-MM-DD HH:MM`) for posts — `date` alone does not work reliably.
|
Reliable tags (others are known-broken): `posts-created-chronological-byyearmonth`, `posts-created-reversechronological`. Use `created` frontmatter (format: `YYYY-MM-DD HH:MM`) for posts.
|
||||||
|
|
||||||
## Release workflow
|
## Release workflow
|
||||||
|
|
||||||
|
|
|
||||||
226
app/index.html
226
app/index.html
|
|
@ -371,6 +371,33 @@ body {
|
||||||
}
|
}
|
||||||
.topbar-nav .nav-item.active { border-left: none; background: var(--nav-active-bg); }
|
.topbar-nav .nav-item.active { border-left: none; background: var(--nav-active-bg); }
|
||||||
|
|
||||||
|
/* ─── Topbar grouped navigation (dropdowns) ─── */
|
||||||
|
.topbar-nav .nav-group { position: relative; }
|
||||||
|
.topbar-nav .nav-trigger {
|
||||||
|
display: flex; align-items: center; gap: 0.25rem;
|
||||||
|
padding: 0.35rem 0.75rem; border-radius: 5px;
|
||||||
|
background: none; border: none; cursor: pointer;
|
||||||
|
color: var(--font-colour); font-size: 0.85rem;
|
||||||
|
font-family: inherit; white-space: nowrap; text-decoration: none; line-height: inherit;
|
||||||
|
}
|
||||||
|
.topbar-nav .nav-trigger:hover,
|
||||||
|
.topbar-nav .nav-group.open > .nav-trigger { background: var(--nav-hover-bg); }
|
||||||
|
.topbar-nav .nav-group.has-active > .nav-trigger { background: var(--nav-active-bg); }
|
||||||
|
.topbar-nav .nav-caret { font-size: 0.6rem; color: var(--font-colour-muted); opacity: 0.55; line-height: 1; }
|
||||||
|
.topbar-nav .nav-dropdown {
|
||||||
|
display: none; position: absolute; top: calc(100% + 4px); left: 0;
|
||||||
|
background: var(--bg-nav); border: 1px solid var(--divider);
|
||||||
|
border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.1);
|
||||||
|
min-width: 160px; z-index: 200; padding: 0.25rem 0;
|
||||||
|
}
|
||||||
|
.topbar-nav .nav-group.open > .nav-dropdown { display: block; }
|
||||||
|
.topbar-nav .nav-dropdown .nav-item {
|
||||||
|
display: block; padding: 0.45rem 1rem;
|
||||||
|
border-left: none; border-radius: 0; white-space: nowrap;
|
||||||
|
}
|
||||||
|
.topbar-nav .nav-dropdown .nav-item:hover { background: var(--nav-hover-bg); }
|
||||||
|
.topbar-nav .nav-dropdown .nav-item.active { background: var(--nav-active-bg); font-weight: 600; }
|
||||||
|
|
||||||
.topbar-actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
|
.topbar-actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
|
||||||
|
|
||||||
.topbar-search { position: relative; }
|
.topbar-search { position: relative; }
|
||||||
|
|
@ -732,6 +759,19 @@ body {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
.layout-topbar .mobile-nav-panel .nav-item.active { border-left: none; font-weight: 600; }
|
.layout-topbar .mobile-nav-panel .nav-item.active { border-left: none; font-weight: 600; }
|
||||||
|
.layout-topbar .mobile-nav-panel .nav-group-row { display: flex; align-items: stretch; }
|
||||||
|
.layout-topbar .mobile-nav-panel .nav-group-row .nav-item { flex: 1; }
|
||||||
|
.layout-topbar .mobile-nav-panel .nav-section-label {
|
||||||
|
flex: 1; display: flex; align-items: center;
|
||||||
|
padding: 0.6rem 1.25rem; font-size: 1rem; color: var(--font-colour); font-weight: 500;
|
||||||
|
}
|
||||||
|
.layout-topbar .mobile-nav-panel .nav-expand-btn {
|
||||||
|
background: none; border: none; cursor: pointer;
|
||||||
|
color: var(--font-colour-muted); padding: 0 1.25rem; font-size: 1.2rem; line-height: 1; flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.layout-topbar .mobile-nav-panel .nav-group-children { display: none; }
|
||||||
|
.layout-topbar .mobile-nav-panel .nav-group-children.open { display: block; }
|
||||||
|
.layout-topbar .mobile-nav-panel .nav-group-children .nav-item { padding-left: 2.5rem; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
|
|
@ -1369,14 +1409,14 @@ function fmtDatetime(dtStr) {
|
||||||
|
|
||||||
function parsePostTagName(name) {
|
function parsePostTagName(name) {
|
||||||
var m = name.match(
|
var m = name.match(
|
||||||
/^posts-(date|datetime)-(chronological|reversechronological)(?:-(byyear|byyearmonth|lastyear|lastmonth))?$/
|
/^posts-created-(chronological|reversechronological)(?:-(byyear|byyearmonth|lastyear|lastmonth))?$/
|
||||||
);
|
);
|
||||||
if (!m) return null;
|
if (!m) return null;
|
||||||
return { field: m[1], order: m[2], modifier: m[3] || null };
|
return { order: m[1], modifier: m[2] || null };
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPostEntries(parsed, options) {
|
function getPostEntries(parsed, options) {
|
||||||
const { field, order, modifier } = parsed;
|
const { order, modifier } = parsed;
|
||||||
|
|
||||||
// Start with posts from search index
|
// Start with posts from search index
|
||||||
let posts = (searchIndex || []).filter(function(e) {
|
let posts = (searchIndex || []).filter(function(e) {
|
||||||
|
|
@ -1389,11 +1429,7 @@ function fmtDatetime(dtStr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field filter
|
// Field filter
|
||||||
if (field === 'datetime') {
|
posts = posts.filter(function(e) { return !!e.created; });
|
||||||
posts = posts.filter(function(e) { return !!e.datetime; });
|
|
||||||
} else {
|
|
||||||
posts = posts.filter(function(e) { return !!e.date; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time-window filter
|
// Time-window filter
|
||||||
if (modifier === 'lastyear' || modifier === 'lastmonth') {
|
if (modifier === 'lastyear' || modifier === 'lastmonth') {
|
||||||
|
|
@ -1402,15 +1438,13 @@ function fmtDatetime(dtStr) {
|
||||||
if (modifier === 'lastyear') cutoff.setDate(cutoff.getDate() - 365);
|
if (modifier === 'lastyear') cutoff.setDate(cutoff.getDate() - 365);
|
||||||
else cutoff.setDate(cutoff.getDate() - 30);
|
else cutoff.setDate(cutoff.getDate() - 30);
|
||||||
posts = posts.filter(function(e) {
|
posts = posts.filter(function(e) {
|
||||||
var raw = field === 'datetime' ? e.datetime.replace(' ', 'T') : e.date;
|
return new Date(e.created.replace(' ', 'T')) >= cutoff;
|
||||||
return new Date(raw) >= cutoff;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort
|
// Sort
|
||||||
var sortKey = field === 'datetime' ? 'datetime' : 'date';
|
|
||||||
posts.sort(function(a, b) {
|
posts.sort(function(a, b) {
|
||||||
var da = a[sortKey] || '', db = b[sortKey] || '';
|
var da = a.created || '', db = b.created || '';
|
||||||
return order === 'chronological' ? da.localeCompare(db) : db.localeCompare(da);
|
return order === 'chronological' ? da.localeCompare(db) : db.localeCompare(da);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1523,7 +1557,6 @@ function fmtDatetime(dtStr) {
|
||||||
|
|
||||||
var opts = tag.options;
|
var opts = tag.options;
|
||||||
var posts = getPostEntries(parsed, opts);
|
var posts = getPostEntries(parsed, opts);
|
||||||
var field = parsed.field;
|
|
||||||
var modifier = parsed.modifier;
|
var modifier = parsed.modifier;
|
||||||
var paginate = opts.paginate || 'no';
|
var paginate = opts.paginate || 'no';
|
||||||
var limitVal = opts.limit || 'all';
|
var limitVal = opts.limit || 'all';
|
||||||
|
|
@ -1532,7 +1565,7 @@ function fmtDatetime(dtStr) {
|
||||||
// Format each entry
|
// Format each entry
|
||||||
var formatted = posts.map(function(p) {
|
var formatted = posts.map(function(p) {
|
||||||
return {
|
return {
|
||||||
display: field === 'datetime' ? fmtDatetime(p.datetime) : fmtDate(p.date),
|
display: fmtDatetime(p.created),
|
||||||
title: p.title,
|
title: p.title,
|
||||||
file: p.file
|
file: p.file
|
||||||
};
|
};
|
||||||
|
|
@ -1565,12 +1598,10 @@ function fmtDatetime(dtStr) {
|
||||||
|
|
||||||
// Grouped by year (or year+month)
|
// Grouped by year (or year+month)
|
||||||
function getYear(p) {
|
function getYear(p) {
|
||||||
var d = field === 'datetime' ? p.datetime : p.date;
|
return p.created ? p.created.substring(0, 4) : 'Unknown';
|
||||||
return d ? d.substring(0, 4) : 'Unknown';
|
|
||||||
}
|
}
|
||||||
function getYearMonth(p) {
|
function getYearMonth(p) {
|
||||||
var d = field === 'datetime' ? p.datetime : p.date;
|
return p.created ? p.created.substring(0, 7) : 'Unknown';
|
||||||
return d ? d.substring(0, 7) : 'Unknown';
|
|
||||||
}
|
}
|
||||||
function monthLabel(ym) {
|
function monthLabel(ym) {
|
||||||
var m = parseInt(ym.substring(5, 7), 10);
|
var m = parseInt(ym.substring(5, 7), 10);
|
||||||
|
|
@ -1809,6 +1840,10 @@ function fmtDatetime(dtStr) {
|
||||||
if (panel) panel.classList.remove('open');
|
if (panel) panel.classList.remove('open');
|
||||||
hamburger.innerHTML = ICONS.menu;
|
hamburger.innerHTML = ICONS.menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.addEventListener('click', () => {
|
||||||
|
document.querySelectorAll('.topbar-nav .nav-group.open').forEach(g => g.classList.remove('open'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSearchWidget() {
|
function buildSearchWidget() {
|
||||||
|
|
@ -2109,18 +2144,141 @@ function fmtDatetime(dtStr) {
|
||||||
tree.forEach(root => renderTreeSection(container, root, 0, groups));
|
tree.forEach(root => renderTreeSection(container, root, 0, groups));
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFlat(container) {
|
function buildTopbarNavItems() {
|
||||||
// Topbar inline: pages only, sorted by global sort, draft-section pages excluded.
|
|
||||||
const byCode = {};
|
const byCode = {};
|
||||||
navSections.forEach(s => { if (s.code) byCode[s.code] = s; });
|
navSections.forEach(s => { if (s.code) byCode[s.code] = s; });
|
||||||
const visible = navData.filter(p => {
|
const items = [];
|
||||||
const sid = p['section-id'];
|
|
||||||
return !sid || !isDraftSection(sid, byCode);
|
// Sections (non-draft), each becomes a dropdown trigger
|
||||||
|
navSections.forEach(s => {
|
||||||
|
if (!s.code || isDraftSection(s.code, byCode)) return;
|
||||||
|
const pages = navData.filter(p => p['section-id'] === s.code && pageShouldDisplay(p));
|
||||||
|
pages.sort((a, b) => ((a.sort ?? 999) - (b.sort ?? 999)) || a.file.localeCompare(b.file));
|
||||||
|
if (!pages.length) return;
|
||||||
|
items.push({ type: 'section', sort: s.sort ?? 999, section: s, pages });
|
||||||
});
|
});
|
||||||
visible.sort((a, b) => ((a.sort ?? 999) - (b.sort ?? 999)) || a.file.localeCompare(b.file));
|
|
||||||
visible.forEach(p => {
|
// Unsectioned pages (or pages whose section isn't in nav), grouped by sort century
|
||||||
const item = makeNavItem(p, 0);
|
const unsectioned = navData.filter(p => {
|
||||||
if (item) container.appendChild(item);
|
if (!pageShouldDisplay(p)) return false;
|
||||||
|
const sid = p['section-id'];
|
||||||
|
return !sid || !byCode[sid];
|
||||||
|
});
|
||||||
|
unsectioned.sort((a, b) => ((a.sort ?? 999) - (b.sort ?? 999)) || a.file.localeCompare(b.file));
|
||||||
|
const centuryMap = new Map();
|
||||||
|
unsectioned.forEach(p => {
|
||||||
|
const c = Math.floor((p.sort ?? 999) / 100);
|
||||||
|
if (!centuryMap.has(c)) centuryMap.set(c, []);
|
||||||
|
centuryMap.get(c).push(p);
|
||||||
|
});
|
||||||
|
for (const [, pgs] of centuryMap) {
|
||||||
|
items.push({ type: 'group', sort: pgs[0].sort ?? 999, primary: pgs[0], children: pgs.slice(1) });
|
||||||
|
}
|
||||||
|
|
||||||
|
items.sort((a, b) => a.sort - b.sort);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeTopbarPageGroup({ primary, children }, isMobile) {
|
||||||
|
const group = el('div', { className: 'nav-group' });
|
||||||
|
const hasChildren = children.length > 0;
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
const row = el('div', { className: 'nav-group-row' });
|
||||||
|
const link = makeNavItem(primary, 0);
|
||||||
|
if (link) row.appendChild(link);
|
||||||
|
if (hasChildren) {
|
||||||
|
const childrenEl = el('div', { className: 'nav-group-children' });
|
||||||
|
children.forEach(p => { const it = makeNavItem(p, 1); if (it) childrenEl.appendChild(it); });
|
||||||
|
const btn = el('button', { className: 'nav-expand-btn', 'aria-label': 'Expand', textContent: '+' });
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
const open = childrenEl.classList.toggle('open');
|
||||||
|
btn.textContent = open ? '−' : '+';
|
||||||
|
});
|
||||||
|
row.appendChild(btn);
|
||||||
|
group.appendChild(row);
|
||||||
|
group.appendChild(childrenEl);
|
||||||
|
} else {
|
||||||
|
group.appendChild(row);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const title = pageDisplayTitle(primary);
|
||||||
|
const trigger = el('a', { className: 'nav-trigger', href: '#' + primary.file, 'data-file': primary.file });
|
||||||
|
trigger.appendChild(el('span', { textContent: title }));
|
||||||
|
if (hasChildren) trigger.appendChild(el('span', { className: 'nav-caret', textContent: '▾' }));
|
||||||
|
group.appendChild(trigger);
|
||||||
|
|
||||||
|
if (hasChildren) {
|
||||||
|
const dropdown = el('div', { className: 'nav-dropdown' });
|
||||||
|
children.forEach(p => { const it = makeNavItem(p, 0); if (it) dropdown.appendChild(it); });
|
||||||
|
group.appendChild(dropdown);
|
||||||
|
group.addEventListener('mouseenter', () => group.classList.add('open'));
|
||||||
|
group.addEventListener('mouseleave', () => group.classList.remove('open'));
|
||||||
|
trigger.addEventListener('click', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
group.classList.toggle('open');
|
||||||
|
navigateTo(primary.file);
|
||||||
|
if (window._closeMobileMenu) window._closeMobileMenu();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
trigger.addEventListener('click', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
navigateTo(primary.file);
|
||||||
|
if (window._closeMobileMenu) window._closeMobileMenu();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeTopbarSection({ section, pages }, isMobile) {
|
||||||
|
const group = el('div', { className: 'nav-group' });
|
||||||
|
const isHidden = section.pagesvisibility === 'hidden';
|
||||||
|
const name = sectionDisplayName(section);
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
const row = el('div', { className: 'nav-group-row' });
|
||||||
|
row.appendChild(el('span', { className: 'nav-section-label', textContent: name }));
|
||||||
|
const childrenEl = el('div', { className: 'nav-group-children' + (isHidden ? '' : ' open') });
|
||||||
|
pages.forEach(p => { const it = makeNavItem(p, 1); if (it) childrenEl.appendChild(it); });
|
||||||
|
const btn = el('button', { className: 'nav-expand-btn', 'aria-label': 'Expand', textContent: isHidden ? '+' : '−' });
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
const open = childrenEl.classList.toggle('open');
|
||||||
|
btn.textContent = open ? '−' : '+';
|
||||||
|
});
|
||||||
|
row.appendChild(btn);
|
||||||
|
group.appendChild(row);
|
||||||
|
group.appendChild(childrenEl);
|
||||||
|
} else {
|
||||||
|
const trigger = el('button', { className: 'nav-trigger', type: 'button' });
|
||||||
|
trigger.appendChild(el('span', { textContent: name }));
|
||||||
|
trigger.appendChild(el('span', { className: 'nav-caret', textContent: '▾' }));
|
||||||
|
trigger.addEventListener('click', e => { e.stopPropagation(); group.classList.toggle('open'); });
|
||||||
|
group.appendChild(trigger);
|
||||||
|
|
||||||
|
const dropdown = el('div', { className: 'nav-dropdown' });
|
||||||
|
pages.forEach(p => { const it = makeNavItem(p, 0); if (it) dropdown.appendChild(it); });
|
||||||
|
group.appendChild(dropdown);
|
||||||
|
|
||||||
|
if (!isHidden) {
|
||||||
|
group.addEventListener('mouseenter', () => group.classList.add('open'));
|
||||||
|
group.addEventListener('mouseleave', () => group.classList.remove('open'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTopbarGrouped(container, isMobile) {
|
||||||
|
const items = buildTopbarNavItems();
|
||||||
|
items.forEach(item => {
|
||||||
|
container.appendChild(
|
||||||
|
item.type === 'group'
|
||||||
|
? makeTopbarPageGroup(item, isMobile)
|
||||||
|
: makeTopbarSection(item, isMobile)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2130,19 +2288,23 @@ function fmtDatetime(dtStr) {
|
||||||
const mobile = document.getElementById('mobileNavLinks');
|
const mobile = document.getElementById('mobileNavLinks');
|
||||||
if (main) {
|
if (main) {
|
||||||
main.innerHTML = '';
|
main.innerHTML = '';
|
||||||
if (topbar) renderFlat(main);
|
if (topbar) renderTopbarGrouped(main, false);
|
||||||
else renderTree(main);
|
else renderTree(main);
|
||||||
}
|
}
|
||||||
if (mobile) {
|
if (mobile) {
|
||||||
mobile.innerHTML = '';
|
mobile.innerHTML = '';
|
||||||
renderTree(mobile);
|
if (topbar) renderTopbarGrouped(mobile, true);
|
||||||
|
else renderTree(mobile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightNav(file) {
|
function highlightNav(file) {
|
||||||
document.querySelectorAll('.nav-item').forEach(item => {
|
document.querySelectorAll('.nav-item, .nav-trigger[data-file]').forEach(item => {
|
||||||
item.classList.toggle('active', item.getAttribute('data-file') === file);
|
item.classList.toggle('active', item.getAttribute('data-file') === file);
|
||||||
});
|
});
|
||||||
|
document.querySelectorAll('.topbar-nav .nav-group').forEach(group => {
|
||||||
|
group.classList.toggle('has-active', !!group.querySelector('[data-file].active'));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Page loading ─────────────────────────────────────────
|
// ─── Page loading ─────────────────────────────────────────
|
||||||
|
|
@ -2189,12 +2351,12 @@ function fmtDatetime(dtStr) {
|
||||||
hydrateMdcmsTags();
|
hydrateMdcmsTags();
|
||||||
|
|
||||||
const firstH = contentEl.querySelector('.md-content h1, .md-content h2');
|
const firstH = contentEl.querySelector('.md-content h1, .md-content h2');
|
||||||
if (firstH && (meta.author || meta.created || meta.date || meta.datetime)) {
|
if (firstH && (meta.author || meta.created)) {
|
||||||
const metaEl = document.createElement('div');
|
const metaEl = document.createElement('div');
|
||||||
metaEl.className = 'page-meta';
|
metaEl.className = 'page-meta';
|
||||||
let metaText = '';
|
let metaText = '';
|
||||||
if (meta.author) metaText += meta.author;
|
if (meta.author) metaText += meta.author;
|
||||||
const displayDate = meta.datetime || meta.date || meta.created;
|
const displayDate = meta.created;
|
||||||
if (displayDate) {
|
if (displayDate) {
|
||||||
if (metaText) metaText += ' | ';
|
if (metaText) metaText += ' | ';
|
||||||
metaText += 'Published ' + formatDate(displayDate);
|
metaText += 'Published ' + formatDate(displayDate);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ If you want to test `MD-CMS` you can grab `samplesite` from the repo and place t
|
||||||
## Reverse chronological (newest first)
|
## Reverse chronological (newest first)
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-date-reversechronological
|
posts-created-reversechronological
|
||||||
limit: 3
|
limit: 3
|
||||||
paginate: no
|
paginate: no
|
||||||
```
|
```
|
||||||
|
|
@ -26,25 +26,25 @@ paginate: no
|
||||||
## Chronological (oldest first)
|
## Chronological (oldest first)
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-date-chronological
|
posts-created-chronological
|
||||||
limit: all
|
limit: all
|
||||||
paginate: none
|
paginate: none
|
||||||
```
|
```
|
||||||
|
|
||||||
## By year (date, reverse chrono)
|
## By year (reverse chrono)
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-date-reversechronological-byyear
|
posts-created-reversechronological-byyear
|
||||||
limit: all
|
limit: all
|
||||||
defaultyear: current
|
defaultyear: current
|
||||||
selectyear: yes
|
selectyear: yes
|
||||||
paginate: none
|
paginate: none
|
||||||
```
|
```
|
||||||
|
|
||||||
## By year+month (datetime, chrono)
|
## By year+month (chrono)
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-datetime-chronological-byyearmonth
|
posts-created-chronological-byyearmonth
|
||||||
limit: all
|
limit: all
|
||||||
defaultyear: 2024
|
defaultyear: 2024
|
||||||
selectyear: yes
|
selectyear: yes
|
||||||
|
|
@ -53,7 +53,7 @@ selectyear: yes
|
||||||
## Last 30 days
|
## Last 30 days
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-date-reversechronological-lastmonth
|
posts-created-reversechronological-lastmonth
|
||||||
limit: all
|
limit: all
|
||||||
paginate: none
|
paginate: none
|
||||||
```
|
```
|
||||||
|
|
@ -61,7 +61,7 @@ paginate: none
|
||||||
## Paginated (2 per page)
|
## Paginated (2 per page)
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-datetime-reversechronological
|
posts-created-reversechronological
|
||||||
limit: 2
|
limit: 2
|
||||||
paginate: yes
|
paginate: yes
|
||||||
```
|
```
|
||||||
|
|
|
||||||
6
mdcms.py
6
mdcms.py
|
|
@ -175,8 +175,6 @@ def scan_and_categorize(directory: Path, site_root: Path, known_codes: set) -> l
|
||||||
"sort": meta.get("sort"),
|
"sort": meta.get("sort"),
|
||||||
"section-id": meta.get("section-id"),
|
"section-id": meta.get("section-id"),
|
||||||
"author": meta.get("author"),
|
"author": meta.get("author"),
|
||||||
"date": str(meta.get("date", "")),
|
|
||||||
"datetime": str(meta.get("datetime", "")),
|
|
||||||
"created": str(meta.get("created", "")),
|
"created": str(meta.get("created", "")),
|
||||||
"modified": str(meta.get("modified", "")),
|
"modified": str(meta.get("modified", "")),
|
||||||
"language": meta.get("language", "en"),
|
"language": meta.get("language", "en"),
|
||||||
|
|
@ -328,8 +326,8 @@ def generate_search_json(
|
||||||
"keywords": r.get("keywords", ""),
|
"keywords": r.get("keywords", ""),
|
||||||
"description": r.get("description", ""),
|
"description": r.get("description", ""),
|
||||||
"author": r.get("author"),
|
"author": r.get("author"),
|
||||||
"date": r.get("date", ""),
|
"created": r.get("created", ""),
|
||||||
"datetime": r.get("datetime", ""),
|
"modified": r.get("modified", ""),
|
||||||
"language": r.get("language", "en"),
|
"language": r.get("language", "en"),
|
||||||
"body": r.get("body", ""),
|
"body": r.get("body", ""),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ Stay up to date with announcements, product updates, and industry insights from
|
||||||
## All Posts
|
## All Posts
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-date-reversechronological-byyear
|
posts-created-reversechronological-byyear
|
||||||
limit: all
|
limit: all
|
||||||
defaultyear: current
|
defaultyear: current
|
||||||
selectyear: yes
|
selectyear: yes
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ Bli oppdatert med kunngjøringer, produktoppdateringer og bransjeinnsikter fra A
|
||||||
## Alle innlegg
|
## Alle innlegg
|
||||||
|
|
||||||
```mdcms
|
```mdcms
|
||||||
posts-date-reversechronological-byyear
|
posts-created-reversechronological-byyear
|
||||||
limit: all
|
limit: all
|
||||||
defaultyear: current
|
defaultyear: current
|
||||||
selectyear: yes
|
selectyear: yes
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Q4 2022 Performance Report
|
title: Q4 2022 Performance Report
|
||||||
date: 2022-11-15
|
created: 2022-11-15 09:00
|
||||||
datetime: 2022-11-15 09:00
|
|
||||||
author: Sarah Chen
|
author: Sarah Chen
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Introducing Advanced Analytics Dashboard
|
title: Introducing Advanced Analytics Dashboard
|
||||||
date: 2023-03-22
|
created: 2023-03-22 14:30
|
||||||
datetime: 2023-03-22 14:30
|
|
||||||
author: David Okonkwo
|
author: David Okonkwo
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Security Update - November 2023
|
title: Security Update - November 2023
|
||||||
date: 2023-11-10
|
created: 2023-11-10 11:45
|
||||||
datetime: 2023-11-10 11:45
|
|
||||||
author: Security Team
|
author: Security Team
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
title: 2024 Product Roadmap
|
title: 2024 Product Roadmap
|
||||||
date: 2024-01-30
|
created: 2024-01-30 10:00
|
||||||
datetime: 2024-01-30 10:00
|
|
||||||
author: David Okonkwo
|
author: David Okonkwo
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Q2 2024 Customer Success Stories
|
title: Q2 2024 Customer Success Stories
|
||||||
date: 2024-07-08
|
created: 2024-07-08 15:20
|
||||||
datetime: 2024-07-08 15:20
|
|
||||||
author: Maria Garcia
|
author: Maria Garcia
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
title: Version 9.0 Released — A New Era
|
title: Version 9.0 Released — A New Era
|
||||||
date: 2026-04-10
|
created: 2026-04-10 13:00
|
||||||
datetime: 2026-04-10 13:00
|
|
||||||
author: Sarah Chen
|
author: Sarah Chen
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue