feat(mindspace): add SEO/GEO delivery, page template catalog, and admin hooks
Memind CI / Test, build, and release guards (push) Has been cancelled
Memind CI / Test, build, and release guards (push) Has been cancelled
Enable optional SEO/GEO injection and discovery routes for confirmed public pages while keeping private pages noindex. Add premium page template skills, portal catalog API, template shop UI, and Baidu push gated by memind_adm config. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import {
|
||||
applyPageTemplatePrefill,
|
||||
buildChatSkillPrompt,
|
||||
CHAT_SKILL_DEFINITIONS,
|
||||
filterChatSkills as filterChatSkillDefinitions,
|
||||
isPageTemplateChatSkillId,
|
||||
mergeChatSkillPromptWithInput,
|
||||
} from '../../chat-skills.mjs';
|
||||
import { buildPublishSkillPrompt, PUBLISH_SKILL_NAME } from './publishSkill';
|
||||
@@ -46,4 +48,8 @@ export function filterChatSkills(
|
||||
}
|
||||
|
||||
export { buildPublishSkillPrompt, PUBLISH_SKILL_NAME };
|
||||
export { mergeChatSkillPromptWithInput };
|
||||
export {
|
||||
applyPageTemplatePrefill,
|
||||
isPageTemplateChatSkillId,
|
||||
mergeChatSkillPromptWithInput,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import type { PageTemplateCatalogItem } from '../types';
|
||||
|
||||
export type TemplateCategoryId =
|
||||
| 'all'
|
||||
| 'travel'
|
||||
| 'commerce'
|
||||
| 'event'
|
||||
| 'content'
|
||||
| 'business'
|
||||
| 'local'
|
||||
| 'form'
|
||||
| 'career';
|
||||
|
||||
export const TEMPLATE_CATEGORIES: { id: TemplateCategoryId; label: string }[] = [
|
||||
{ id: 'all', label: '全部' },
|
||||
{ id: 'travel', label: '旅游出行' },
|
||||
{ id: 'commerce', label: '电商促销' },
|
||||
{ id: 'event', label: '活动邀请' },
|
||||
{ id: 'content', label: '内容展示' },
|
||||
{ id: 'business', label: '商业办公' },
|
||||
{ id: 'local', label: '本地生活' },
|
||||
{ id: 'form', label: '表单问卷' },
|
||||
{ id: 'career', label: '职业简历' },
|
||||
];
|
||||
|
||||
export const TEMPLATE_CATEGORY_MAP: Record<string, TemplateCategoryId> = {
|
||||
'page-template-travel': 'travel',
|
||||
'page-template-hotel': 'travel',
|
||||
'page-template-campaign': 'commerce',
|
||||
'page-template-product-grid': 'commerce',
|
||||
'page-template-event': 'event',
|
||||
'page-template-wedding': 'event',
|
||||
'page-template-charity': 'event',
|
||||
'page-template-blog': 'content',
|
||||
'page-template-portfolio': 'content',
|
||||
'page-template-photography': 'content',
|
||||
'page-template-podcast': 'content',
|
||||
'page-template-saas': 'business',
|
||||
'page-template-agency': 'business',
|
||||
'page-template-startup': 'business',
|
||||
'page-template-course': 'business',
|
||||
'page-template-restaurant': 'local',
|
||||
'page-template-fitness': 'local',
|
||||
'page-template-realestate': 'local',
|
||||
'page-template-survey': 'form',
|
||||
'page-template-resume': 'career',
|
||||
};
|
||||
|
||||
export type TemplateSortId = 'hot' | 'price-asc' | 'price-desc' | 'name';
|
||||
|
||||
export const TEMPLATE_SORT_OPTIONS: { id: TemplateSortId; label: string }[] = [
|
||||
{ id: 'hot', label: '热门优先' },
|
||||
{ id: 'price-asc', label: '价格从低到高' },
|
||||
{ id: 'price-desc', label: '价格从高到低' },
|
||||
{ id: 'name', label: '名称 A-Z' },
|
||||
];
|
||||
|
||||
export function filterTemplatesByCategory(
|
||||
items: PageTemplateCatalogItem[],
|
||||
category: TemplateCategoryId,
|
||||
) {
|
||||
if (category === 'all') return items;
|
||||
return items.filter((item) => TEMPLATE_CATEGORY_MAP[item.skillName] === category);
|
||||
}
|
||||
|
||||
export function sortTemplates(items: PageTemplateCatalogItem[], sort: TemplateSortId) {
|
||||
const next = [...items];
|
||||
switch (sort) {
|
||||
case 'hot':
|
||||
next.sort((a, b) => (b.usageCount ?? 0) - (a.usageCount ?? 0) || a.label.localeCompare(b.label, 'zh'));
|
||||
break;
|
||||
case 'price-asc':
|
||||
next.sort((a, b) => a.priceCents - b.priceCents || a.label.localeCompare(b.label, 'zh'));
|
||||
break;
|
||||
case 'price-desc':
|
||||
next.sort((a, b) => b.priceCents - a.priceCents || a.label.localeCompare(b.label, 'zh'));
|
||||
break;
|
||||
case 'name':
|
||||
next.sort((a, b) => a.label.localeCompare(b.label, 'zh'));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
Reference in New Issue
Block a user