Repository: GraphiteEditor/Graphite
File: frontend/src/components/floating-menus/NodeCatalog.svelte (Svelte)

Code before:
			.sort((a, b) => a[0].localeCompare(b[0]))
			.sort((a, b) => {
				const aIndex = START_CATEGORIES_ORDER.findIndex((x) => a[0].startsWith(x));
				const bIndex = START_CATEGORIES_ORDER.findIndex((x) => b[0].startsWith(x));
				if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
				if (aIndex !== -1) return -1;
				if (bIndex !== -1) return 1;
				return 0;
			})
			.sort((a, b) => {
				const aIndex = END_CATEGORIES_ORDER.findIndex((x) => a[0].startsWith(x));
				const bIndex = END_CATEGORIES_ORDER.findIndex((x) => b[0].startsWith(x));
				if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
				if (aIndex !== -1) return 1;
				if (bIndex !== -1) return -1;
				return 0;
			});
	}

	onMount(() => {
		setTimeout(() => nodeSearchInput?.focus(), 0);
	});
</script>

<div class="node-catalog">
	<TextInput placeholder="Search Nodes... (or type:InputType)" value={searchTerm} on:value={({ detail }) => (searchTerm = detail)} bind:this={nodeSearchInput} />
	<div class="list-results" on:wheel|passive|stopPropagation>
		{#each nodeCategories as nodeCategory}
			<details open={nodeCategory[1].open}>
				<summary>
					<TextLabel>{nodeCategory[0]}</TextLabel>
				</summary>
				{#each nodeCategory[1].nodes as nodeType}
					<TextButton {disabled} label={nodeType.name} tooltip={$nodeGraph.nodeDescriptions.get(nodeType.name)} action={() => dispatch("selectNodeType", nodeType.name)} />
				{/each}
			</details>
		{:else}
			<TextLabel>No search results</TextLabel>
		{/each}
	</div>
</div>

<style lang="scss" global>
	.node-catalog {
		max-height: 40vh;
		min-width: 250px;
		display: flex;
		flex-direction: column;
		align-items: stretch;

		.text-input {

Review comment (suggestion):
I'm not quite sure of the UX of having the type as the search term. This prevents the user from further filtering down the options.

For example vector data is used by many nodes (and more will be added over time), so the user may wish to further filter them with a keyword.

Code after:
			} else {
				categories.set(node.category, {
					open,
					nodes: [node],
				});
			}
		});

		const START_CATEGORIES_ORDER = ["UNCATEGORIZED", "General", "Value", "Math", "Style"];
		const END_CATEGORIES_ORDER = ["Debug"];
		return Array.from(categories)
			.sort((a, b) => a[0].localeCompare(b[0]))
			.sort((a, b) => {
				const aIndex = START_CATEGORIES_ORDER.findIndex((x) => a[0].startsWith(x));
				const bIndex = START_CATEGORIES_ORDER.findIndex((x) => b[0].startsWith(x));
				if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
				if (aIndex !== -1) return -1;
				if (bIndex !== -1) return 1;
				return 0;
			})
			.sort((a, b) => {
				const aIndex = END_CATEGORIES_ORDER.findIndex((x) => a[0].startsWith(x));
				const bIndex = END_CATEGORIES_ORDER.findIndex((x) => b[0].startsWith(x));
				if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex;
				if (aIndex !== -1) return 1;
				if (bIndex !== -1) return -1;
				return 0;
			});
	}

	onMount(() => {
		setTimeout(() => nodeSearchInput?.focus(), 0);
	});
</script>

<div class="node-catalog">
	<TextInput placeholder="Search Nodes..." value={searchTerm} on:value={({ detail }) => (searchTerm = detail)} bind:this={nodeSearchInput} />
	<div class="list-results" on:wheel|passive|stopPropagation>
		{#each nodeCategories as nodeCategory}
			<details open={nodeCategory[1].open}>
				<summary>
					<TextLabel>{nodeCategory[0]}</TextLabel>
				</summary>
				{#each nodeCategory[1].nodes as nodeType}
					<TextButton {disabled} label={nodeType.name} tooltip={$nodeGraph.nodeDescriptions.get(nodeType.name)} action={() => dispatch("selectNodeType", nodeType.name)} />
				{/each}
			</details>
		{:else}
			<TextLabel>No search results</TextLabel>
		{/each}
	</div>