diff --git a/components/SettingsUI/MarketplaceBrowseModal.tsx b/components/SettingsUI/MarketplaceBrowseModal.tsx index 67709e2..b7389cc 100644 --- a/components/SettingsUI/MarketplaceBrowseModal.tsx +++ b/components/SettingsUI/MarketplaceBrowseModal.tsx @@ -20,26 +20,85 @@ export const MarketplaceBrowseModal: React.FC = ({ onClose, }) => { const [searchQuery, setSearchQuery] = useState(""); + const [languageFilter, setLanguageFilter] = useState(""); + const [typeFilter, setTypeFilter] = useState(""); + + const allTemplates = useMemo(() => { + return [...PREDEFINED_TEMPLATES, ...COMMUNITY_TEMPLATES]; + }, []); + + const availableLanguages = useMemo(() => { + const langs = new Set(); + allTemplates.forEach((t) => { + if (t.language) langs.add(t.language); + }); + return Array.from(langs).sort(); + }, [allTemplates]); + + const availableTypes = useMemo(() => { + const types = new Set(); + allTemplates.forEach((t) => { + if (t.type) types.add(t.type); + }); + return Array.from(types).sort(); + }, [allTemplates]); const filteredTemplates = useMemo(() => { - const allTemplates = [...PREDEFINED_TEMPLATES, ...COMMUNITY_TEMPLATES]; - return allTemplates.filter( - (t) => + return allTemplates.filter((t) => { + const matchesSearch = t.name.toLowerCase().includes(searchQuery.toLowerCase()) || - t.description.toLowerCase().includes(searchQuery.toLowerCase()), - ); - }, [searchQuery]); + t.description.toLowerCase().includes(searchQuery.toLowerCase()); + + const matchesLanguage = + !languageFilter || t.language === languageFilter; + const matchesType = !typeFilter || t.type === typeFilter; + + return matchesSearch && matchesLanguage && matchesType; + }); + }, [allTemplates, searchQuery, languageFilter, typeFilter]); return (

Template Marketplace

- +
+ + {availableLanguages.length > 0 && ( + + )} + {availableTypes.length > 0 && ( + + )} +
@@ -65,6 +124,16 @@ export const MarketplaceBrowseModal: React.FC = ({ ? "Built-in" : "Community"} + {template.type && ( + + {template.type} + + )} + {template.language && ( + + {template.language} + + )} {template.authorGithub && (
by{" "} diff --git a/components/SettingsUI/TemplateEditorModal.tsx b/components/SettingsUI/TemplateEditorModal.tsx index 36d3d4e..1efe01e 100644 --- a/components/SettingsUI/TemplateEditorModal.tsx +++ b/components/SettingsUI/TemplateEditorModal.tsx @@ -28,6 +28,8 @@ export const TemplateEditorModal: React.FC = ({ const [isIdUnlocked, setIsIdUnlocked] = useState(false); const [isAuthorUnlocked, setIsAuthorUnlocked] = useState(false); const [description, setDescription] = useState(template?.description || ""); + const [language, setLanguage] = useState(template?.language || ""); + const [type, setType] = useState(template?.type || ""); const [authorGithub, setAuthorGithub] = useState( template?.authorGithub || "", ); @@ -74,12 +76,24 @@ export const TemplateEditorModal: React.FC = ({ id: templateId, name: name.trim(), description: description.trim(), + language: language.trim() || undefined, + type: type.trim() || undefined, authorGithub: authorGithub.trim() || undefined, statuses: statusesWithTemplateId, }; onSave(savedTemplate); - }, [id, name, description, authorGithub, statuses, isValid, onSave]); + }, [ + id, + name, + description, + language, + type, + authorGithub, + statuses, + isValid, + onSave, + ]); const handleNameChange = useCallback( (val: string) => { @@ -218,6 +232,30 @@ export const TemplateEditorModal: React.FC = ({ /> + + + + + + + + { - // Either matches an original marketplace template ID + // Either matches an original predefined template const matchesPredefined = PREDEFINED_TEMPLATES.some( (pt) => pt.id === template.id || @@ -14,9 +17,13 @@ export const isCustomTemplate = (template: StatusTemplate): boolean => { ); if (matchesPredefined) return false; - // Or has metadata from marketplace - const hasMetadata = !!template.authorGithub; - if (hasMetadata) return false; + // Or matches an original community template + const matchesCommunity = COMMUNITY_TEMPLATES.some( + (ct) => + ct.id === template.id || + ct.name.toLowerCase() === template.name.toLowerCase(), + ); + if (matchesCommunity) return false; return true; }; @@ -25,7 +32,11 @@ export const isCustomTemplate = (template: StatusTemplate): boolean => { * Check if a marketplace template has been modified by the user */ export const isTemplateModified = (template: StatusTemplate): boolean => { - const original = PREDEFINED_TEMPLATES.find( + const allMarketplaceTemplates = [ + ...PREDEFINED_TEMPLATES, + ...COMMUNITY_TEMPLATES, + ]; + const original = allMarketplaceTemplates.find( (pt) => pt.id === template.id || pt.name.toLowerCase() === template.name.toLowerCase(), @@ -104,4 +115,3 @@ export const generateTemplateId = ( return id; }; -