spb/company-atlas
Public
Python 66.3%
TypeScript 22.7%
JavaScript 8.6%
HTML 1.4%
CSS 0.7%
1/**2 * Event-type visual language (spec §21 taxonomy). Each type maps to a CSS token `--ev-<key>` declared in globals.css3 * (both themes), a short label and a lucide icon name used by `EventTypeBadge`. Unknown types fall back to `other`.4 */5export type EventTypeKey =6 | 'product'7 | 'pricing'8 | 'hiring'9 | 'leadership'10 | 'location'11 | 'financing'12 | 'ma'13 | 'partnership'14 | 'strategy'15 | 'technology'16 | 'legal'17 | 'marketing'18 | 'developer'19 | 'security'20 | 'operations'21 | 'sustainability'22 | 'investor_relations'23 | 'communication'24 | 'other';2526export interface EventStyle {27 key: EventTypeKey;28 label: string;29 /** CSS color expression, usable in `style={{ color }}`. */30 color: string;31 soft: string;32}3334const TYPE_TO_KEY: Record<string, EventTypeKey> = {35 PRODUCT: 'product',36 PRICING: 'pricing',37 HIRING: 'hiring',38 LEADERSHIP: 'leadership',39 LOCATION: 'location',40 FINANCING: 'financing',41 'M&A': 'ma',42 MA: 'ma',43 M_A: 'ma',44 MERGER: 'ma',45 ACQUISITION: 'ma',46 PARTNERSHIP: 'partnership',47 STRATEGY: 'strategy',48 TECHNOLOGY: 'technology',49 LEGAL: 'legal',50 MARKETING: 'marketing',51 DEVELOPER: 'developer',52 SECURITY: 'security',53 OPERATIONS: 'operations',54 SUSTAINABILITY: 'sustainability',55 INVESTOR_RELATIONS: 'investor_relations',56 COMMUNICATION: 'communication',57 NEWS: 'communication',58 OTHER: 'other',59};6061const LABELS: Record<EventTypeKey, string> = {62 product: 'Product',63 pricing: 'Pricing',64 hiring: 'Hiring',65 leadership: 'Leadership',66 location: 'Location',67 financing: 'Financing',68 ma: 'M&A',69 partnership: 'Partnership',70 strategy: 'Strategy',71 technology: 'Technology',72 legal: 'Legal',73 marketing: 'Marketing',74 developer: 'Developer',75 security: 'Security',76 operations: 'Operations',77 sustainability: 'Sustainability',78 investor_relations: 'Investor relations',79 communication: 'Communication',80 other: 'Other',81};8283export function eventKey(type: string | null | undefined): EventTypeKey {84 if (!type) return 'other';85 return TYPE_TO_KEY[type.toUpperCase()] ?? 'other';86}8788export function eventStyle(type: string | null | undefined): EventStyle {89 const key = eventKey(type);90 return { key, label: LABELS[key], color: `var(--ev-${key})`, soft: `color-mix(in srgb, var(--ev-${key}) 12%, transparent)` };91}9293/** Ordered list for filters and legends (the spec taxonomy order). */94export const EVENT_TYPES: string[] = [95 'PRODUCT',96 'PRICING',97 'HIRING',98 'LEADERSHIP',99 'LOCATION',100 'FINANCING',101 'M&A',102 'PARTNERSHIP',103 'STRATEGY',104 'TECHNOLOGY',105 'LEGAL',106 'MARKETING',107 'DEVELOPER',108 'SECURITY',109 'OPERATIONS',110 'SUSTAINABILITY',111 'INVESTOR_RELATIONS',112 'COMMUNICATION',113 'OTHER',114];115116export function eventTypeLabel(type: string | null | undefined): string {117 return LABELS[eventKey(type)];118}119120/** Subtype → careful human label. Anything unknown is humanised, never invented. */121const SUBTYPE_LABELS: Record<string, string> = {122 PRODUCT_LAUNCH: 'Product launch',123 PRODUCT_REMOVAL: 'Product no longer listed',124 PRODUCT_RENAME: 'Product renamed',125 PRICE_INCREASE: 'Price increase',126 PRICE_DECREASE: 'Price decrease',127 NEW_PRICING_TIER: 'New pricing tier',128 PRICING_CHANGE: 'Pricing change',129 JOB_COUNT_INCREASE: 'Job count increase',130 JOB_COUNT_DECREASE: 'Job count decrease',131 NEW_JOB: 'New listing',132 JOB_REMOVED: 'Listing no longer visible',133 NEW_EXECUTIVE: 'New executive listed',134 EXECUTIVE_REMOVED: 'Executive no longer listed',135 LEADERSHIP_CHANGE: 'Leadership page changed',136 NEW_OFFICE: 'New office listed',137 OFFICE_REMOVED: 'Office no longer listed',138 NEW_LOCATION: 'New location listed',139 COUNTRY_EXPANSION: 'Country expansion',140 NEW_PARTNERSHIP: 'New partnership',141 ACQUISITION: 'Acquisition',142 DIVESTITURE: 'Divestiture',143 API_LAUNCH: 'API launch',144 DOCUMENTATION_CHANGE: 'Documentation change',145 DOC_CHANGE: 'Documentation change',146 TERMS_CHANGE: 'Terms change',147 BRAND_REPOSITIONING: 'Brand repositioning',148 NEWS_RELEASE: 'News release',149 SECURITY_NOTICE: 'Security notice',150};151export function subtypeLabel(sub: string | null | undefined): string {152 if (!sub) return '';153 return SUBTYPE_LABELS[sub.toUpperCase()] ?? sub.replace(/[_-]+/g, ' ').toLowerCase().replace(/^\w/, (c) => c.toUpperCase());154}155