Files
Jonathan Miller 79724b5bc9 feat(ui): add generic combo-multiselect component
Add a reusable multiselect dropdown component inspired by the issue
sidebar label picker, but decoupled from issue-specific logic.

Components:
- templates/shared/combolist.tmpl — generic template accepting Items,
  Name, Title, SelectedValues parameters
- web_src/js/features/combo-multiselect.ts — lightweight JS init that
  handles check/uncheck, search, and hidden input updates
- web_src/css/modules/combo-multiselect.css — check-mark visibility
  and selected-items list styling

Usage in any template:
  {{template "shared/combolist" dict
    "Name" "channels"
    "Title" "Update Channels"
    "Items" .AvailableChannels
    "SelectedValues" .SelectedChannelIDs
  }}

Items must have .Value and .Label fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 11:41:08 -05:00

47 lines
1.9 KiB
Handlebars

{{/*
Generic multiselect combo list component.
Provides a dropdown with search, checkable items, and a selected-items display list.
Parameters:
Name - form input name (required)
Title - display label (required)
Items - slice of items, each must have .Value and .Label fields
SelectedValues - comma-separated string of selected values
Placeholder - search input placeholder (optional, defaults to "Filter...")
EmptyText - text when nothing is selected (optional)
Disabled - whether the control is disabled (optional)
Icon - gear icon shown next to title (optional, defaults to "octicon-gear")
*/}}
<div class="combo-multiselect" data-field-name="{{.Name}}">
<input class="combo-value" name="{{.Name}}" type="hidden" value="{{.SelectedValues}}">
<div class="ui dropdown full-width {{if .Disabled}}disabled{{end}}">
<a class="fixed-text muted">
<strong>{{.Title}}</strong> {{if not .Disabled}}{{svg (or .Icon "octicon-gear")}}{{end}}
</a>
<div class="menu">
{{if .Items}}
<div class="ui icon search input">
<i class="icon">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{or .Placeholder (ctx.Locale.Tr "search.filter")}}">
</div>
<div class="scrolling menu">
<a class="item clear-selection" href="#">{{ctx.Locale.Tr "repo.issues.new.clear_labels"}}</a>
<div class="divider"></div>
{{range .Items}}
<a class="item" data-value="{{.Value}}">
<span class="item-check-mark">{{svg "octicon-check" 16}}</span>
<span class="item-label">{{.Label}}</span>
</a>
{{end}}
</div>
{{else}}
<div class="item disabled">{{or .EmptyText (ctx.Locale.Tr "repo.issues.new.no_items")}}</div>
{{end}}
</div>
</div>
<div class="ui list combo-multiselect-list">
<span class="item empty-list">{{or .EmptyText "None"}}</span>
</div>
</div>