Skip to content

Conversation

@a0m0rajab
Copy link
Contributor

@a0m0rajab a0m0rajab commented Oct 18, 2025

(This is a demo PR, will check the functionality later today)

This pull request enhances the templates UI by adding a search input for filtering templates by language and introduces an event-driven mechanism for template filtering. The main changes are grouped below:

UI Enhancements:

  • Added a search input field (<input id="templates-search-input" ...>) to the templates navigation, allowing users to filter templates by language.

Event-Driven Filtering:

  • Introduced an inline script that listens for user input in the search field, debounces the input, and emits a templates:filter custom event with the current query. This enables other scripts to react and perform the actual filtering logic.

What type of PR is this? (check all applicable)

  • ✨ Feature
  • 🐛 Bug Fix
  • 📝 Documentation Update
  • 🎨 Stylea
  • ♻️ Code Refactor
  • 🔥 Performance Improvements
  • ✅ Test
  • 🤖 Build
  • 🔁 CI
  • 📦 Chore (Release)
  • ⏩ Revert
  • 🌐 Internationalization / Translation

Description

Related Tickets & Documents

Fixes #900
This pull request adds a search/filter feature to the templates section in the templates.html file, allowing users to filter templates by language. It introduces a search input UI and emits a custom event to enable template filtering functionality.

User interface improvements:

  • Added a search input field (<input id="templates-search-input" ...>) to the templates navigation for filtering templates by language.

Interactivity and event handling:

  • Added an inline script that listens to input changes on the search field, debounces user input, and emits a templates:filter custom event with the current query to enable live filtering of templates.

Mobile & Desktop Screenshots/Recordings

Added tests?

  • 👍 yes
  • 🙅 no, because they aren't needed
  • 🙋 no, because I need help

Added to documentations?

  • 📓 docs (./docs)
  • 📕 storybook (./storybook)
  • 📜 README.md
  • 🙅 no documentation needed

[optional] Are there any post-deployment tasks we need to perform?

[optional] What gif best describes this PR or how it makes you feel?

Summary by CodeRabbit

  • New Features

    • Templates search: debounced, client-side search to filter starter and user templates in real time.
  • Style

    • New modal size variant and updated templates panel layout for improved responsiveness and height.
  • Bug Fixes / UX

    • Starter list adjusted (some templates renamed/removed) and many starter aliases added for better discoverability.
  • Documentation

    • Added localization entries for the templates search UI and new starter titles.

✏️ Tip: You can customize this high-level summary in your review settings.

@netlify
Copy link

netlify bot commented Oct 18, 2025

Deploy Preview for livecodes ready!

Name Link
🔨 Latest commit 0b1d802
🔍 Latest deploy log https://app.netlify.com/projects/livecodes/deploys/69778137e0a2010007d81e61
😎 Deploy Preview https://deploy-preview-901--livecodes.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link

coderabbitai bot commented Oct 18, 2025

Walkthrough

Adds a client-side templates search input and FlexSearch-based indexing/filtering, wires index population into starter and user template loading, exposes search-related UI helpers, adds many template aliases and i18n keys, and introduces a modal size variant and related style/layout changes.

Changes

Cohort / File(s) Summary
Templates UI & Search
src/livecodes/html/templates.html, src/livecodes/UI/templates.ts, src/livecodes/UI/selectors.ts, src/livecodes/styles/inc-modal.scss
Inserted #templates-search-input and surrounding container; implemented FlexSearch index management and debounced search (initTemplatesSearchIndex, addTemplateToIndex, setupTemplatesSearch); exported selector getTemplatesSearchInput; added .large-fixed modal style and search layout CSS.
Core wiring & modals
src/livecodes/core.ts, src/livecodes/UI/import.ts, src/livecodes/UI/open.ts, src/livecodes/UI/command-menu-actions.ts
Initialized and populated templates search index from core flow; added data-id to list items; changed import modal to size: 'large-fixed'; removed two starter template options from command menu list.
Starter template metadata
src/livecodes/templates/starter/* (many files)
Added or updated aliases across many starter templates; switched some titles to runtime translations (wasm-related); adjusted alias values (e.g., pyodidepython-wasm, clangcpp-wasm).
Internationalization
src/livecodes/i18n/locales/en/translation.lokalise.json, src/livecodes/i18n/locales/en/translation.ts
Added templates.search.label and templates.search.placeholder; added starter translation keys (csharp-wasm, d3, phaser, python-wasm).
Types & SDK surface
src/livecodes/models.ts, src/sdk/models.ts
Extended ModalOptions.size with large-fixed; introduced TemplateAlias type and updated template alias typing, removing pyodide and clang from previous TemplateName union.
Stories & examples
storybook/stories/EmbedOptions/template.stories.ts
Updated example story templates: PythonPyodidepython-wasm, CppClangcpp-wasm.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(220,240,255,0.5)
    participant User
    end
    rect rgba(255,240,220,0.5)
    participant SearchInput as "templates-search-input (DOM)"
    end
    rect rgba(220,255,230,0.5)
    participant TemplatesModule as "templates.ts"
    end
    rect rgba(240,230,255,0.5)
    participant FlexSearch as "FlexSearch Index"
    end
    rect rgba(255,230,230,0.5)
    participant DOMLists as "starter/user <li> lists"
    end

    User->>SearchInput: type query
    SearchInput->>TemplatesModule: input event
    TemplatesModule->>TemplatesModule: debounce(150ms)
    TemplatesModule->>FlexSearch: query index
    FlexSearch-->>TemplatesModule: return matched ids
    TemplatesModule->>DOMLists: show/hide items based on ids
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes include scope creep beyond the original search feature: extensive alias additions to all starter templates, removal of 'pyodide' and 'clang' from TemplateName union, and modal size updates. These go beyond the basic search functionality. Consider separating alias additions, template name deprecations, and modal styling updates into separate, focused PRs. Reduce this PR to core search implementation and integration.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main feature addition—search functionality for templates—which aligns with the primary changes in the changeset.
Linked Issues check ✅ Passed The PR fully implements the feature requested in issue #900: a searchable UI for templates with filtering by language/keywords, flexsearch-powered indexing, and enhanced discoverability.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7344c78 and ef91608.

📒 Files selected for processing (1)
  • src/livecodes/html/templates.html (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Redirect rules - livecodes
  • GitHub Check: Header rules - livecodes
  • GitHub Check: Pages changed - livecodes
🔇 Additional comments (1)
src/livecodes/html/templates.html (1)

36-55: Script logic is sound; confirm filtering implementation is planned.

The inline script correctly debounces input (150ms), emits a templates:filter custom event with the query value, and uses defensive null checks. The implementation is event-driven as intended, allowing other scripts to listen and filter templates accordingly.

Since this is described as a demo PR pending actual filtering logic, verify that:

  • Event listeners consuming the templates:filter event will be implemented separately.
  • The event dispatch to #templates-container aligns with where filter listeners will be attached.

Copy link
Collaborator

@hatemhosny hatemhosny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @a0m0rajab

I have added some comments.

</div>

<!-- Inline: emit a "templates:filter" event with the current query so other scripts can perform filtering -->
<script>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can move the logic to src/livecodes/UI/templates.ts.
Think of the html here as the "view" while the logic in templates.ts as the "controller" in MVC pattern.

Also if you do that, you can directly manipulate DOM elements e.g. add display: none; without having to emit events.

var val = e.target.value || '';
// debounce to avoid excessive events while typing
clearTimeout(timeout);
timeout = setTimeout(function () { emit(val.trim()); }, 150);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a debounce function here that you can re-use.

</li>
<li class="templates-search">
<label for="templates-search-input" class="visually-hidden" data-i18n="templates.search.label">Search templates</label>
<input id="templates-search-input" type="search" placeholder="Filter languages..." aria-label="Filter templates by language" />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change "Filter languages..." to "Search templates...". And then we can search by title, languages and others (e.g. tags).

Also, after you finish your edits, please run npm run i18n-export to regenerate the i18n json and fix this build error.

@hatemhosny
Copy link
Collaborator

Thank you @DevAbdelrahmanSayed
It is still in progress.
If @a0m0rajab doesn't have the time to complete it, you are welcome to work on it.

@a0m0rajab
Copy link
Contributor Author

Hi, thanks for mentioning me in the comments! I’d love to work on and finish this, but I might not be able to get to it before the weekend.

Just a general note, it’s usually nice to check in with the PR contributor first before escalating to the maintainers. It tends to come across as more polite and professional. If the contributor doesn’t respond for a while and the PR becomes stale, then escalating to the maintainers would make sense.

@hatemhosny
Copy link
Collaborator

Salam @a0m0rajab 👋

If you do not have enough time to finish this, do you mind other contributors to continue the work you have started?
@TutTrue has started a PR here.

Much appreciated.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/livecodes/UI/templates.ts`:
- Around line 66-87: Call setupTemplatesSearch() after the templates UI is
mounted so the '#templates-search-input' listener is attached and can filter
'#templates-user' items; specifically, add a call to setupTemplatesSearch() at
the end of handleNew() when the modal opens (or immediately after
loadUserTemplates() finishes rendering items) to ensure the search input is
wired up to the filtering logic in setupTemplatesSearch.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/livecodes/core.ts`:
- Around line 3279-3281: After templates finish rendering and
setupTemplatesSearch() is called, reapply the current query so any keystrokes
typed during load are honored: locate setupTemplatesSearch() and the search
input element it wires up (e.g., the searchInput/inputs used by
setupTemplatesSearch) and programmatically trigger the existing input handler by
dispatching an 'input' event (or calling the filter function directly) on that
element immediately after setupTemplatesSearch() so the list is filtered with
the current value.

Comment on lines 3279 to 3281
});
setupTemplatesSearch();
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Reapply the filter after templates render to honor early input.
If the user types while templates are still loading, the list is appended afterward and won’t be filtered until the next input event. Triggering one after render preserves the typed query.

🛠️ Suggested fix
           starterTemplates.forEach((template) => {
             const link = createStarterTemplateLink(template, starterTemplatesList, baseUrl);
             eventsManager.addEventListener(
               link,
               'click',
               (event) => {
                 event.preventDefault();
                 loadStarterTemplate(template.name, /* checkSaved= */ false);
               },
               false,
             );
           });
           setupTemplatesSearch();
+          const searchInput = document.getElementById(
+            'templates-search-input',
+          ) as HTMLInputElement | null;
+          searchInput?.dispatchEvent(new Event('input', { bubbles: true }));
🤖 Prompt for AI Agents
In `@src/livecodes/core.ts` around lines 3279 - 3281, After templates finish
rendering and setupTemplatesSearch() is called, reapply the current query so any
keystrokes typed during load are honored: locate setupTemplatesSearch() and the
search input element it wires up (e.g., the searchInput/inputs used by
setupTemplatesSearch) and programmatically trigger the existing input handler by
dispatching an 'input' event (or calling the filter function directly) on that
element immediately after setupTemplatesSearch() so the list is filtered with
the current value.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/livecodes/UI/templates.ts`:
- Around line 67-90: Update setupTemplatesSearch to accept a templatesContainer
parameter and scope DOM queries to it: change setupTemplatesSearch() to
setupTemplatesSearch(templatesContainer?: Element | Document) and use
templatesContainer.querySelectorAll('#templates-starter li') and
templatesContainer.querySelectorAll('#templates-user li') (falling back to
document when templatesContainer is not provided or not yet mounted). Also
ensure filterTemplates and debouncedFilter refer to the scoped items and keep
the existing debounce and input handler logic but query the input from
templatesContainer (or document) so timing and scoping issues are resolved.
- Line 31: Call setupTemplatesSearch after mounting or pass the templates
container into it so it queries the input within the detached node instead of
using document.getElementById; update the setupTemplatesSearch signature to
accept a container parameter (e.g., Element or HTMLElement) and replace
document.getElementById('templates-search-input') with
container.querySelector('#templates-search-input'), then ensure the call site
(where templatesContainer is created/mounted) passes templatesContainer into
setupTemplatesSearch.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/livecodes/UI/templates.ts`:
- Around line 71-89: Filtering only runs on user input so dynamically added
templates from loadUserTemplates() bypass the current query; after new templates
are inserted call filterTemplates(input.value.trim()) (or dispatch an 'input'
event on input) to reapply the current query, e.g., at the end of
loadUserTemplates() or its promise callback so filterTemplates, debouncedFilter
and input stay in sync with newly added items.

Comment on lines 71 to 89
const filterTemplates = (query: string) => {
const mainItems = container.querySelectorAll('#templates-starter li');
const userItems = container.querySelectorAll('#templates-user li');
const items = Array.from(mainItems).concat(Array.from(userItems));
items.forEach((item) => {
const text = item.textContent?.toLowerCase() || '';
const matches = text.includes(query.toLowerCase());
(item as HTMLElement).style.display = matches ? '' : 'none';
});
};

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

input.addEventListener('input', (e: Event) => {
const val = (e.target as HTMLInputElement).value || '';
debouncedFilter(val);
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Reapply filter when templates are loaded dynamically.

Filtering only runs on input events; if a user types a query and then loadUserTemplates() inserts items later, those new items won’t be filtered until the user types again. Consider reapplying the current query after templates load (e.g., call filterTemplates(input.value.trim()) or dispatch an input event) so the results stay consistent.

🤖 Prompt for AI Agents
In `@src/livecodes/UI/templates.ts` around lines 71 - 89, Filtering only runs on
user input so dynamically added templates from loadUserTemplates() bypass the
current query; after new templates are inserted call
filterTemplates(input.value.trim()) (or dispatch an 'input' event on input) to
reapply the current query, e.g., at the end of loadUserTemplates() or its
promise callback so filterTemplates, debouncedFilter and input stay in sync with
newly added items.

@a0m0rajab
Copy link
Contributor Author

@hatemhosny Salam,

just finished the PR, checked the lints locally and fixed them, will wait the actions to check them again.

Sorry for the delay, did not expect myself to not be able to work on this in the last few weeks!

@hatemhosny
Copy link
Collaborator

hatemhosny commented Jan 25, 2026

Thanks a lot @a0m0rajab
I like this feature. I think it is very useful indeed.

While reviewing your changes I found many fixes I needed to add in how I loaded and displayed templates.
I have also added aliases for templates (e.g. so that typing js would find javascript, etc).
In addition, I thought the search functionality would benefit from using flexsearch, which we are already using to search saved projects (e.g. for fuzzy search, and to search in tags and languages).

I have added these changes and started a PR to your branch here.
I would appreciate if you have a look and let me know what you think.

Thank you very much ❤️

@a0m0rajab
Copy link
Contributor Author

@hatemhosny thanks for that, I just merged the changes you made!

I was not aware of the already implemented search functionality.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/livecodes/styles/inc-modal.scss`:
- Around line 67-69: The .large-fixed modal variant sets height: 85vh but is
still constrained by the base `#modal` rule max-height: 72vh; update the
.large-fixed selector (in inc-modal.scss) to also override the max-height (e.g.,
max-height: 85vh or max-height: none) so the declared height can take effect;
ensure you target the same specificity as `#modal` (or increase specificity) so
the override is applied.

In `@src/livecodes/UI/templates.ts`:
- Around line 99-130: The search handler in setupTemplatesSearch currently
listens to the 'keyup' event which misses paste/clear/IME updates; change the
listener on the input element returned by getTemplatesSearchInput to listen for
the 'input' event instead and call the existing debouncedFilter((e.target as
HTMLInputElement).value || '') so paste/clear/IME changes trigger
filterTemplates; keep the existing debounce and trimming behavior and leave
filterTemplates, debouncedFilter, and searchIndex usage unchanged.

In `@src/sdk/models.ts`:
- Around line 1461-1493: The TemplateAlias union currently contains a duplicate
entry 'prolog' which is already defined as a canonical value in TemplateName;
remove 'prolog' from the TemplateAlias type (leave it only in TemplateName) to
avoid redundancy and ambiguity, and run type checks to ensure no callers expect
'prolog' to be treated as an alias (update any uses referencing TemplateAlias if
needed).
♻️ Duplicate comments (1)
src/livecodes/core.ts (1)

3271-3305: Reapply the active search query after templates finish loading.
If the user types while templates are still loading, newly appended items won’t be filtered until the next keystroke. Trigger the existing filter handler (or dispatch the same event) after render.

🧹 Nitpick comments (1)
storybook/stories/EmbedOptions/template.stories.ts (1)

45-51: LGTM!

The template values are correctly updated from 'pyodide' to 'python-wasm' and from 'clang' to 'cpp-wasm', aligning with the updated TemplateName type.

Consider renaming the export variables from PythonPyodide/CppClang to PythonWasm/CppWasm for consistency with the new naming convention, though this is optional.

Comment on lines +67 to +69
&.large-fixed {
height: 85vh;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

large-fixed height is still capped by the default max-height.
#modal sets max-height: 72vh, so height: 85vh won’t take effect. Consider overriding max-height in the variant.

🐛 Proposed fix
  &.large-fixed {
    height: 85vh;
+    max-height: 85vh;
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
&.large-fixed {
height: 85vh;
}
&.large-fixed {
height: 85vh;
max-height: 85vh;
}
🤖 Prompt for AI Agents
In `@src/livecodes/styles/inc-modal.scss` around lines 67 - 69, The .large-fixed
modal variant sets height: 85vh but is still constrained by the base `#modal` rule
max-height: 72vh; update the .large-fixed selector (in inc-modal.scss) to also
override the max-height (e.g., max-height: 85vh or max-height: none) so the
declared height can take effect; ensure you target the same specificity as
`#modal` (or increase specificity) so the override is applied.

@sonarqubecloud
Copy link

@hatemhosny
Copy link
Collaborator

Thanks a lot @a0m0rajab

@hatemhosny hatemhosny merged commit 7e230d2 into live-codes:develop Jan 26, 2026
15 checks passed
@livecodes-ci
Copy link
Contributor

livecodes-ci bot commented Jan 26, 2026

i18n Actions

Source PR has been merged into the default branch.

Maintainers can comment .i18n-update-push to trigger the i18n update workflow and push the changes to Lokalise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: Add search option to languages panel

2 participants