feat(search): add multi-token regex and wildcard support (#211)
* feat(search): add multi-token regex and wildcard support * feat(ui): add layout toggle button in Model Manager header
This commit is contained in:
25
src/App.vue
25
src/App.vue
@@ -80,8 +80,25 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleLayout = () => {
|
||||||
|
// flip the flat setting
|
||||||
|
const newValue = !config.flat.value
|
||||||
|
config.flat.value = newValue
|
||||||
|
|
||||||
|
// persist so it survives reloads
|
||||||
|
app.ui?.settings.setSettingValue('ModelManager.UI.Flat', newValue)
|
||||||
|
|
||||||
|
// close the current dialog (because it is keepAlive)
|
||||||
|
dialog.closeAll()
|
||||||
|
|
||||||
|
// reopen with the new layout
|
||||||
|
openManagerDialog()
|
||||||
|
}
|
||||||
|
|
||||||
const openManagerDialog = () => {
|
const openManagerDialog = () => {
|
||||||
const { cardWidth, gutter, aspect, flat } = config
|
const { cardWidth, gutter, aspect, flat } = config
|
||||||
|
// choose icon depending on current layout
|
||||||
|
const layoutIcon = flat.value ? 'pi pi-folder-open' : 'pi pi-th-large'
|
||||||
|
|
||||||
if (firstOpenManager.value) {
|
if (firstOpenManager.value) {
|
||||||
models.refresh(true)
|
models.refresh(true)
|
||||||
@@ -99,6 +116,14 @@ onMounted(() => {
|
|||||||
icon: 'mdi mdi-folder-search-outline text-lg',
|
icon: 'mdi mdi-folder-search-outline text-lg',
|
||||||
command: openModelScanning,
|
command: openModelScanning,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'toggle-layout',
|
||||||
|
icon: layoutIcon,
|
||||||
|
command: toggleLayout,
|
||||||
|
tooltip: flat.value
|
||||||
|
? t('switchToFolderView')
|
||||||
|
: t('switchToFlatView'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'refresh',
|
key: 'refresh',
|
||||||
icon: 'pi pi-refresh',
|
icon: 'pi pi-refresh',
|
||||||
|
|||||||
@@ -225,17 +225,33 @@ const list = computed(() => {
|
|||||||
return !item.isFolder
|
return !item.isFolder
|
||||||
})
|
})
|
||||||
|
|
||||||
const filterList = pureModels.filter((model) => {
|
function buildRegex(raw: string): RegExp {
|
||||||
const showAllModel = currentType.value === allType
|
try {
|
||||||
|
// Escape regex specials, then restore * wildcards as .*
|
||||||
|
const escaped = raw
|
||||||
|
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||||
|
.replace(/\\\*/g, '.*')
|
||||||
|
return new RegExp(escaped, 'i') // case-insensitive
|
||||||
|
} catch (e) {
|
||||||
|
return new RegExp(raw, 'i')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterList = pureModels.filter((model) => {
|
||||||
|
const showAllModel = currentType.value === allType
|
||||||
const matchType = showAllModel || model.type === currentType.value
|
const matchType = showAllModel || model.type === currentType.value
|
||||||
|
|
||||||
const filter = searchContent.value?.toLowerCase() ?? ''
|
const rawFilter = searchContent.value ?? ''
|
||||||
const matchSubFolder = model.subFolder.toLowerCase().includes(filter)
|
const tokens = rawFilter.split(/\s+/).filter(Boolean)
|
||||||
const matchName = model.basename.toLowerCase().includes(filter)
|
const regexes = tokens.map(buildRegex)
|
||||||
|
|
||||||
return matchType && (matchSubFolder || matchName)
|
// Require every token to match either the folder or the name
|
||||||
})
|
const matchesAll = regexes.every((re) =>
|
||||||
|
re.test(model.subFolder) || re.test(model.basename)
|
||||||
|
)
|
||||||
|
|
||||||
|
return matchType && matchesAll
|
||||||
|
})
|
||||||
|
|
||||||
let sortStrategy: (a: Model, b: Model) => number = () => 0
|
let sortStrategy: (a: Model, b: Model) => number = () => 0
|
||||||
switch (sortOrder.value) {
|
switch (sortOrder.value) {
|
||||||
@@ -262,6 +278,7 @@ const list = computed(() => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const contentStyle = computed(() => ({
|
const contentStyle = computed(() => ({
|
||||||
gridTemplateColumns: `repeat(auto-fit, ${cardSize.value.width}px)`,
|
gridTemplateColumns: `repeat(auto-fit, ${cardSize.value.width}px)`,
|
||||||
gap: `${gutter}px`,
|
gap: `${gutter}px`,
|
||||||
|
|||||||
Reference in New Issue
Block a user