Skip to content

Commit 71194c9

Browse files
committed
use flexsearch for templates
1 parent 8f4bccf commit 71194c9

3 files changed

Lines changed: 68 additions & 12 deletions

File tree

src/livecodes/UI/open.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const createOpenItem = (
2323
isTemplate = false,
2424
) => {
2525
const li = document.createElement('li');
26+
li.dataset.id = item.id;
2627
list.appendChild(li);
2728

2829
const link = document.createElement('a');

src/livecodes/UI/templates.ts

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { templatesScreen } from '../html';
22
import type { EventsManager, Template } from '../models';
3-
import { debounce } from '../utils/utils';
3+
import { debounce, loadScript } from '../utils/utils';
4+
import { flexSearchUrl } from '../vendors';
45
import { getTemplatesSearchInput } from './selectors';
56

7+
let searchIndex: Promise<any> | undefined;
8+
69
export const createTemplatesContainer = (eventsManager: EventsManager) => {
710
const div = document.createElement('div');
811
div.innerHTML = templatesScreen;
@@ -28,11 +31,12 @@ export const createTemplatesContainer = (eventsManager: EventsManager) => {
2831
};
2932

3033
export const createStarterTemplateLink = (
31-
template: Template,
34+
template: Template & { id: string },
3235
starterTemplatesList: HTMLElement | null,
3336
baseUrl: string,
3437
) => {
3538
const li = document.createElement('li');
39+
li.dataset.id = template.id;
3640
const link = document.createElement('a');
3741
link.href = '?template=' + template.name;
3842
link.innerHTML = `
@@ -59,26 +63,68 @@ export const noUserTemplates = () => `
5963
</div>
6064
`;
6165

66+
export const initTemplatesSearchIndex = () => {
67+
searchIndex = loadScript(flexSearchUrl, 'FlexSearch').then(
68+
async (FlexSearch: any) =>
69+
new FlexSearch.Document({
70+
index: ['name', 'title', 'description', 'aliases', 'tags', 'languages'],
71+
tokenize: 'full',
72+
worker: true,
73+
}),
74+
);
75+
};
76+
77+
export const addTemplateToIndex = ({
78+
id,
79+
title,
80+
name = '',
81+
description = '',
82+
aliases = [],
83+
tags = [],
84+
languages = [],
85+
}: {
86+
id: string;
87+
title: string;
88+
name?: string;
89+
description?: string;
90+
aliases?: string[];
91+
tags?: string[];
92+
languages?: string[];
93+
}) => {
94+
searchIndex?.then((index) => {
95+
index.add({ id, name, title, description, aliases, tags, languages });
96+
});
97+
};
98+
6299
export const setupTemplatesSearch = (container: HTMLElement) => {
63100
const input = getTemplatesSearchInput(container);
64101
if (!input) return;
65102

66103
const filterTemplates = (query: string) => {
67-
const mainItems = container.querySelectorAll('#templates-starter li');
68-
const userItems = container.querySelectorAll('#templates-user li');
69-
const items = Array.from(mainItems).concat(Array.from(userItems));
70-
items.forEach((item) => {
71-
const text = item.textContent?.toLowerCase() || '';
72-
const matches = text.includes(query.toLowerCase());
73-
(item as HTMLElement).style.display = matches ? '' : 'none';
104+
searchIndex?.then(async (index) => {
105+
const mainItems = container.querySelectorAll(
106+
'#templates-starter li',
107+
) as NodeListOf<HTMLElement>;
108+
const userItems = container.querySelectorAll('#templates-user li') as NodeListOf<HTMLElement>;
109+
const items = Array.from(mainItems).concat(Array.from(userItems));
110+
111+
const result =
112+
query === ''
113+
? null
114+
: (await index.searchAsync(query)).map((field: any) => field.result).flat();
115+
116+
items.forEach((item) => {
117+
(item as HTMLElement).style.display =
118+
query === '' || result.includes(item.dataset.id as string) ? '' : 'none';
119+
});
74120
});
75121
};
76122

77123
const debouncedFilter = debounce((val: string) => {
78124
filterTemplates(val.trim());
79125
}, 150);
80126

81-
input.addEventListener('input', (e: Event) => {
127+
input.addEventListener('keyup', (e: Event) => {
82128
const val = (e.target as HTMLInputElement).value || '';
83129
debouncedFilter(val);
84130
});

src/livecodes/core.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getPlaygroundUrl } from '../sdk';
22
import {
3+
addTemplateToIndex,
34
createLoginContainer,
45
createOpenItem,
56
createProjectInfoUI,
@@ -10,6 +11,7 @@ import {
1011
displayLoggedOut,
1112
getFullscreenButton,
1213
getResultElement,
14+
initTemplatesSearchIndex,
1315
loadingMessage,
1416
noUserTemplates,
1517
} from './UI';
@@ -3174,6 +3176,7 @@ const handleNew = () => {
31743176
getLanguageByAlias,
31753177
true,
31763178
);
3179+
addTemplateToIndex(item);
31773180

31783181
if (defaultTemplate === item.id) {
31793182
link.parentElement?.classList.add('selected');
@@ -3256,6 +3259,7 @@ const handleNew = () => {
32563259
};
32573260

32583261
const createTemplatesUI = async () => {
3262+
initTemplatesSearchIndex();
32593263
const starterTemplatesList = UI.getStarterTemplatesList(templatesContainer);
32603264
if (!starterTemplatesList) return;
32613265
starterTemplatesList.innerHTML = '';
@@ -3267,8 +3271,13 @@ const handleNew = () => {
32673271
getTemplates()
32683272
.then((starterTemplates) => {
32693273
loadingText?.remove();
3270-
starterTemplates.forEach((template) => {
3271-
const link = createStarterTemplateLink(template, starterTemplatesList, baseUrl);
3274+
starterTemplates.forEach((template, id) => {
3275+
const link = createStarterTemplateLink(
3276+
{ id: String(id), ...template },
3277+
starterTemplatesList,
3278+
baseUrl,
3279+
);
3280+
addTemplateToIndex({ id: String(id), ...template });
32723281
eventsManager.addEventListener(
32733282
link,
32743283
'click',

0 commit comments

Comments
 (0)