managarten/packages/shared-help-content/src/merger.ts
Till-JS ee42b6cc76 feat: major update with network graphs, themes, todo extensions, and more
## New Features

### Network Graph Visualization (Contacts, Calendar, Todo)
- D3.js force simulation for physics-based layout
- Zoom & pan with mouse/touchpad
- Keyboard shortcuts: +/- zoom, 0 reset, Esc deselect, / search, F focus
- Filtering by tags, company/location/project, connection strength
- Shared components in @manacore/shared-ui

### Central Tags API (mana-core-auth)
- CRUD endpoints for tags
- Schema: tags table with userId, name, color, app
- Shared tag components in @manacore/shared-ui

### Custom Themes System
- Theme editor with live preview and color picker
- Community theme gallery
- Theme sharing (public, unlisted, private)
- Backend API in mana-core-auth

### Todo App Extensions
- Glass-pill design for task input and items
- Settings page with 20+ preferences
- Task edit modal with inline editing
- Statistics page with visualizations
- PWA support with offline capabilities
- Multiple kanban boards

### Contacts App Features
- Duplicate detection
- Photo upload
- Batch operations
- Enhanced favorites page with multiple view modes
- Alphabet view improvements
- Search modal

### Help System
- @manacore/shared-help-content
- @manacore/shared-help-ui
- @manacore/shared-help-types

### Other Features
- Themes page for all apps
- Referral system frontend
- CommandBar (global search)
- Skeleton loaders
- Settings page improvements

## Bug Fixes
- Network graph simulation initialization
- Database schema TEXT for user_id columns (Better Auth compatibility)
- Various styling fixes

## Documentation
- Daily report for 2025-12-10
- CI/CD deployment guide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 02:37:46 +01:00

119 lines
3.4 KiB
TypeScript

/**
* Content Merger
* Merges central help content with app-specific content
*/
import type { HelpContent, MergeContentOptions } from '@manacore/shared-help-types';
/**
* Filter content items by locale and app
*/
function filterItems<T extends { language: string; appSpecific?: boolean; apps?: string[] }>(
items: T[],
locale: string,
appId: string
): T[] {
return items.filter((item) => {
// Filter by language
if (item.language !== locale) {
return false;
}
// Include non-app-specific items
if (!item.appSpecific) {
return true;
}
// Include app-specific items for this app
return item.apps?.includes(appId) ?? false;
});
}
/**
* Merge two arrays, optionally replacing items with same ID
*/
function mergeArrays<T extends { id: string }>(
central: T[],
appSpecific: T[],
overrideById: boolean
): T[] {
if (!overrideById) {
return [...central, ...appSpecific];
}
const appIds = new Set(appSpecific.map((item) => item.id));
const filtered = central.filter((item) => !appIds.has(item.id));
return [...filtered, ...appSpecific];
}
/**
* Sort items by order property
*/
function sortByOrder<T extends { order?: number }>(items: T[]): T[] {
return [...items].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
}
/**
* Merge central help content with app-specific content
*/
export function mergeContent(
central: HelpContent,
appSpecific: Partial<HelpContent>,
options: MergeContentOptions
): HelpContent {
const { appId, locale, overrideById = true } = options;
// Filter central content by locale and app
const filteredCentral: HelpContent = {
faq: filterItems(central.faq, locale, appId),
features: filterItems(central.features, locale, appId),
shortcuts: filterItems(central.shortcuts, locale, appId),
gettingStarted: filterItems(central.gettingStarted, locale, appId),
changelog: filterItems(central.changelog, locale, appId),
contact: central.contact?.language === locale ? central.contact : null,
};
// Filter app-specific content
const filteredApp: Partial<HelpContent> = {
faq: appSpecific.faq ? filterItems(appSpecific.faq, locale, appId) : [],
features: appSpecific.features ? filterItems(appSpecific.features, locale, appId) : [],
shortcuts: appSpecific.shortcuts ? filterItems(appSpecific.shortcuts, locale, appId) : [],
gettingStarted: appSpecific.gettingStarted
? filterItems(appSpecific.gettingStarted, locale, appId)
: [],
changelog: appSpecific.changelog ? filterItems(appSpecific.changelog, locale, appId) : [],
contact: appSpecific.contact?.language === locale ? appSpecific.contact : null,
};
// Merge and sort
return {
faq: sortByOrder(mergeArrays(filteredCentral.faq, filteredApp.faq ?? [], overrideById)),
features: sortByOrder(
mergeArrays(filteredCentral.features, filteredApp.features ?? [], overrideById)
),
shortcuts: sortByOrder(
mergeArrays(filteredCentral.shortcuts, filteredApp.shortcuts ?? [], overrideById)
),
gettingStarted: sortByOrder(
mergeArrays(filteredCentral.gettingStarted, filteredApp.gettingStarted ?? [], overrideById)
),
changelog: sortByOrder(
mergeArrays(filteredCentral.changelog, filteredApp.changelog ?? [], overrideById)
),
contact: filteredApp.contact ?? filteredCentral.contact,
};
}
/**
* Create an empty HelpContent object
*/
export function createEmptyContent(): HelpContent {
return {
faq: [],
features: [],
shortcuts: [],
gettingStarted: [],
changelog: [],
contact: null,
};
}