From 07aff2705868c0baa45cb85174f254fff344b7bd Mon Sep 17 00:00:00 2001 From: HighImKevin Date: Sun, 11 Oct 2026 08:25:56 -0400 Subject: [PATCH] Support hiding items in Custom Item sections, and allow adding items to default Kefin custom item sections --- configuration/homeScreen-configuration.js | 15 +- configuration/homeScreenAdvancedEditor.css | 70 ++++++- configuration/homeScreenAdvancedEditor.js | 33 ++- configuration/homeScreenCustomItemsEditor.js | 209 +++++++++++++++++-- configuration/homeScreenEditorProfiles.js | 4 +- configuration/homeScreenSectionEditor.css | 21 ++ configuration/homeScreenSectionEditor.js | 23 +- scripts/cardBuilder.js | 3 +- scripts/sectionHelper.js | 3 +- 9 files changed, 338 insertions(+), 43 deletions(-) diff --git a/configuration/homeScreen-configuration.js b/configuration/homeScreen-configuration.js index 5f49877..2b060a8 100644 --- a/configuration/homeScreen-configuration.js +++ b/configuration/homeScreen-configuration.js @@ -1008,20 +1008,7 @@ } const browseSection = studiosGroup.sections.find((s) => s?.id === BROWSE_BY_STUDIO_SECTION_ID); - const catalogNames = new Set(BROWSE_BY_STUDIO_CATALOG.map((entry) => entry.name)); - - // Prune items no longer in Kefin catalog (even when catalog is otherwise fully resolved) - if (browseSection && Array.isArray(browseSection.items)) { - const beforeLen = browseSection.items.length; - browseSection.items = browseSection.items.filter( - (item) => item?.Name && catalogNames.has(item.Name) - ); - if (browseSection.items.length !== beforeLen) { - hasChanges = true; - LOG(`Pruned ${beforeLen - browseSection.items.length} browse-by-studio studios not in catalog`); - } - } - + // Append-only: do not prune user-kept studios that leave the Kefin catalog const existingItems = Array.isArray(browseSection?.items) ? browseSection.items : []; if (browseSection && isBrowseByStudioCatalogFullyResolved(existingItems)) { diff --git a/configuration/homeScreenAdvancedEditor.css b/configuration/homeScreenAdvancedEditor.css index 2787297..a51aa75 100644 --- a/configuration/homeScreenAdvancedEditor.css +++ b/configuration/homeScreenAdvancedEditor.css @@ -563,8 +563,9 @@ display: flex; flex-wrap: wrap; gap: 1em; - justify-content: center; + justify-content: start; padding: 0.5em 0 1em; + align-items: center; } :is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) .hsse-custom-item-tile, @@ -576,6 +577,68 @@ gap: 0.35em; } +.hsse-custom-items-grid > * { + max-width: 120px; +} +.listItemBodyText.hsse-custom-item-tile-label { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} +.hsse-custom-item-edit-badge { + position: absolute; + bottom: 0.2em; + right: 0.2em; +} +.hsse-custom-item-actions > * { + height: 25px; + width: 25px; + display: flex; + justify-content: center; +} + +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-tile.is-hidden + .hsse-custom-item-tile-image, +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-tile.is-hidden + .hsse-custom-item-tile-label { + opacity: 0.4; + filter: grayscale(0.35); +} + +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-actions { + display: flex; + align-items: center; + justify-content: center; + gap: 0.2em; +} + +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-action, +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-trash { + font-size: 0; + padding: 0.3em; + min-height: 0; + min-width: 0; + line-height: 1; +} + +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-action:disabled { + opacity: 0.35; + cursor: default; +} + +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-action-icon, +:is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) + .hsse-custom-item-trash-icon { + font-size: 1.1rem; +} + :is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) .hsse-custom-item-tile-image, :is([data-modal-id="kefin-homescreen-section-editor"], [data-modal-id="kefin-homescreen-section-create-flow"]) .hsse-custom-item-add-tile { width: auto; @@ -1598,7 +1661,7 @@ display: grid !important; } -/* Item source — show only the panel matching the active source (profile rules still gate custom items on non-full profiles) */ +/* Item source — show only the panel matching the active source */ .hsae-root[data-item-source="jellyfin"] .hsae-custom-items-group, .hsae-root[data-item-source="jellyfin"] .hsae-external-list-group { display: none !important; @@ -1660,6 +1723,7 @@ } .hsse-image-preview img { - height: 200px; + height: 120px; + max-width: 120px; width: auto !important; } \ No newline at end of file diff --git a/configuration/homeScreenAdvancedEditor.js b/configuration/homeScreenAdvancedEditor.js index 7bbf4c9..fbc6b27 100644 --- a/configuration/homeScreenAdvancedEditor.js +++ b/configuration/homeScreenAdvancedEditor.js @@ -656,6 +656,23 @@ return window.KefinHomeScreenCustomItemsEditor; } + /** User-created / custom-group sections may delete items; default Kefin sections may only hide. */ + function shouldAllowCustomItemRemove(state) { + const id = state?.section?.id || ''; + if (state?.context?.isCustomSection === true) return true; + if (state?.section?.isCustom === true) return true; + if (id.startsWith('custom-')) return true; + return false; + } + + function getAdvancedCustomItemsOptions(state) { + const customEditor = getCustomItemsEditor(); + if (!customEditor?.getCustomItemsOptions) return {}; + return customEditor.getCustomItemsOptions({ + allowRemove: shouldAllowCustomItemRemove(state) + }); + } + function getCachePresets() { const cache = window.KefinHomeConfig2?.CACHE || window.KefinHomeConfig2?.CACHE_CONFIG || {}; return [ @@ -1110,7 +1127,7 @@ const customEditor = getCustomItemsEditor(); if (customEditor && state.itemSource === 'custom') { - customEditor.collectCustomItemsFromForm(root, state, customEditor.getCustomItemsOptions()); + customEditor.collectCustomItemsFromForm(root, state, getAdvancedCustomItemsOptions(state)); } if (state.itemSource === 'external') { @@ -1863,15 +1880,19 @@ function buildCustomItemsHTML(state) { const customEditor = getCustomItemsEditor(); + const allowRemove = shouldAllowCustomItemRemove(state); const html = customEditor - ? customEditor.renderCustomItemsHTML(state, customEditor.getCustomItemsOptions()) + ? customEditor.renderCustomItemsHTML(state, getAdvancedCustomItemsOptions(state)) : '
Custom items editor not available.
'; + const groupDesc = allowRemove + ? 'Create cards with custom images and links' + : 'Reorder or hide cards. Default section items cannot be deleted.'; return ` -
+
Custom Items
-
Create cards with custom images and links
+
${escapeHtml(groupDesc)}
${html}
@@ -2636,7 +2657,7 @@ const liveState = getLiveEditorState(dialog); const customItemsGroup = dialog.querySelector('.hsae-custom-items-group'); if (isProfileFieldActive(root, customItemsGroup) && customEditor && liveState?.customItems) { - customEditor.collectCustomItemsFromForm(dialog, liveState, customEditor.getCustomItemsOptions()); + customEditor.collectCustomItemsFromForm(dialog, liveState, getAdvancedCustomItemsOptions(liveState)); section.items = liveState.customItems.map(customEditor.buildStaticItemFromDraft).filter(Boolean); } else if (!Array.isArray(section.items)) { section.items = []; @@ -3373,7 +3394,7 @@ if (action?.startsWith('hsae-')) { const customEditor = getCustomItemsEditor(); if (customEditor && state.itemSource === 'custom') { - customEditor.handleAction(action, actionEl, root, state, customEditor.getCustomItemsOptions(), () => refreshEditorBody(modalInstance)); + customEditor.handleAction(action, actionEl, root, state, getAdvancedCustomItemsOptions(state), () => refreshEditorBody(modalInstance)); } return; } diff --git a/configuration/homeScreenCustomItemsEditor.js b/configuration/homeScreenCustomItemsEditor.js index 0bbf0cb..68ab8c3 100644 --- a/configuration/homeScreenCustomItemsEditor.js +++ b/configuration/homeScreenCustomItemsEditor.js @@ -37,9 +37,14 @@ addItem: 'wizard-add-custom-item', removeItem: 'wizard-remove-custom-item', toggleImages: 'wizard-toggle-custom-images', + toggleHide: 'wizard-toggle-custom-item-hide', + moveLeft: 'wizard-move-custom-item-left', + moveRight: 'wizard-move-custom-item-right', ...(options.actions || {}) }, - intro: options.intro !== false + intro: options.intro !== false, + // Default Kefin sections pass false — hide only, never delete + allowRemove: options.allowRemove !== false }; } @@ -61,7 +66,8 @@ backdropUrl: '', squareUrl: '', bannerUrl: '', - logoUrl: '' + logoUrl: '', + hidden: false }; } @@ -77,6 +83,9 @@ draft.squareUrl = item.squareUrl || ''; draft.bannerUrl = item.bannerUrl || ''; draft.logoUrl = item.logoUrl || ''; + draft.hidden = item.hidden === true; + if (item.Id || item.id) draft.id = item.Id || item.id; + if (item.Type) draft.type = item.Type; return draft; } @@ -114,6 +123,33 @@ state.customItemAdditionalExpanded = next; } + function swapCustomItemExpanded(state, fromIndex, toIndex) { + if (!state.customItemAdditionalExpanded) return; + const a = state.customItemAdditionalExpanded[fromIndex]; + const b = state.customItemAdditionalExpanded[toIndex]; + if (a === undefined && b === undefined) return; + if (b === undefined) delete state.customItemAdditionalExpanded[fromIndex]; + else state.customItemAdditionalExpanded[fromIndex] = b; + if (a === undefined) delete state.customItemAdditionalExpanded[toIndex]; + else state.customItemAdditionalExpanded[toIndex] = a; + } + + function moveCustomItemExpanded(state, fromIndex, toIndex) { + if (!state.customItemAdditionalExpanded || fromIndex === toIndex) return; + const next = {}; + const moved = state.customItemAdditionalExpanded[fromIndex]; + Object.entries(state.customItemAdditionalExpanded).forEach(([key, value]) => { + const i = parseInt(key, 10); + if (Number.isNaN(i) || i === fromIndex) return; + let dest = i; + if (fromIndex < toIndex && i > fromIndex && i <= toIndex) dest = i - 1; + else if (fromIndex > toIndex && i >= toIndex && i < fromIndex) dest = i + 1; + next[dest] = value; + }); + if (moved !== undefined) next[toIndex] = moved; + state.customItemAdditionalExpanded = next; + } + function hasValidCustomItems(items) { return (items || []).some(item => item.name?.trim() && item.posterUrl?.trim()); } @@ -138,11 +174,13 @@ if (value) provided[key] = value; }); - const item = { Name: name, Type: 'Folder' }; + const item = { Name: name, Type: draft.type || 'Folder' }; + if (draft.id) item.Id = draft.id; const cardUrl = draft.cardUrl?.trim(); if (cardUrl) item.cardUrl = cardUrl; const cardFooter = draft.cardFooter?.trim(); if (cardFooter) item.cardFooter = cardFooter; + if (draft.hidden === true) item.hidden = true; const keys = Object.keys(provided); if (keys.length === 1 && provided.posterUrl) { @@ -177,9 +215,20 @@ } } + function resolvePreviewUrl(url) { + const kefinTweaksRoot = window.KefinTweaksConfig?.kefinTweaksRoot || ''; + const serverId = (typeof ApiClient !== 'undefined' && typeof ApiClient.serverId === 'function') + ? ApiClient.serverId() + : ''; + return String(url || '') + .replace(/\$\{kefinTweaksRoot\}/g, kefinTweaksRoot) + .replace(/\$\{serverId\}/g, serverId) + .trim(); + } + function updateCustomImagePreview(imgEl, url) { if (!imgEl) return; - const trimmed = (url || '').trim(); + const trimmed = resolvePreviewUrl(url); if (!trimmed) { imgEl.removeAttribute('src'); imgEl.style.display = 'none'; @@ -268,19 +317,41 @@ `; } - function renderCustomItemTileHTML(index, item, canRemove, options) { + function renderCustomItemTileHTML(index, item, canRemove, options, itemCount) { const opts = getOptions(options); const label = item.name?.trim() || `Item ${index + 1}`; + const isHidden = item.hidden === true; + const canMoveLeft = index > 0; + const canMoveRight = index < itemCount - 1; + const hideIcon = isHidden ? 'visibility_off' : 'visibility'; + const hideLabel = isHidden ? `Show ${label}` : `Hide ${label}`; + const removeTitle = canRemove + ? `Remove ${label}` + : (opts.allowRemove === false + ? 'Default section items cannot be deleted — hide instead' + : `Remove ${label}`); + return ` -
+
${escapeHtml(label)}
- +
+ + + + +
`; } @@ -319,7 +390,7 @@ const opts = getOptions(options); ensureCustomItemsInitialized(state); const items = state.customItems; - const canRemove = items.length > 1; + const canRemove = opts.allowRemove !== false && items.length > 1; return `
@@ -329,7 +400,7 @@

Name and poster required. Link and other images optional.

` : ''}
- ${items.map((item, index) => renderCustomItemTileHTML(index, item, canRemove, opts)).join('')} + ${items.map((item, index) => renderCustomItemTileHTML(index, item, canRemove, opts, items.length)).join('')} @@ -339,6 +410,48 @@ `; } + function reindexTileDom(tile, index, itemCount) { + if (!tile) return; + tile.dataset.customItemIndex = String(index); + tile.querySelectorAll('[data-item-index]').forEach((el) => { + el.dataset.itemIndex = String(index); + }); + const tileImg = tile.querySelector('img[data-tile-index]'); + if (tileImg) tileImg.dataset.tileIndex = String(index); + + // Action order: left | hide | delete | right + const actions = tile.querySelectorAll('.hsse-custom-item-actions .hsse-custom-item-action'); + if (actions.length >= 4) { + actions[0].disabled = index <= 0; + actions[3].disabled = index >= itemCount - 1; + } + } + + function swapAdjacentCustomItemTiles(root, fromIndex, toIndex) { + if (!root || fromIndex === toIndex) return false; + const grid = root.querySelector('.hsse-custom-items-grid'); + if (!grid) return false; + const a = grid.querySelector(`[data-custom-item-index="${fromIndex}"]`); + const b = grid.querySelector(`[data-custom-item-index="${toIndex}"]`); + if (!a || !b) return false; + + const aNext = a.nextSibling; + const bNext = b.nextSibling; + if (aNext === b) { + grid.insertBefore(b, a); + } else if (bNext === a) { + grid.insertBefore(a, b); + } else { + grid.insertBefore(a, bNext); + grid.insertBefore(b, aNext); + } + + const itemCount = grid.querySelectorAll('[data-custom-item-index]').length; + reindexTileDom(a, toIndex, itemCount); + reindexTileDom(b, fromIndex, itemCount); + return true; + } + function handleAction(action, el, root, state, options, onRefresh) { const opts = getOptions(options); const actions = opts.actions; @@ -371,6 +484,7 @@ break; } case actions.removeItem: { + if (opts.allowRemove === false) break; const removeIndex = parseInt(el.dataset.itemIndex, 10); if (state.customItems.length <= 1 || Number.isNaN(removeIndex)) break; if (state.customItemEditorIndex === removeIndex) { @@ -403,6 +517,74 @@ if (typeof onRefresh === 'function') onRefresh(root); break; } + case actions.toggleHide: { + const hideIndex = parseInt(el.dataset.itemIndex, 10); + if (Number.isNaN(hideIndex) || !state.customItems?.[hideIndex]) break; + collectCustomItemsFromForm(root, state, opts); + const item = state.customItems[hideIndex]; + item.hidden = !item.hidden; + + // Remove, then reinsert at the target slot among remaining items + state.customItems.splice(hideIndex, 1); + let insertAt; + if (item.hidden === true) { + // Hidden items stay at the end + insertAt = state.customItems.length; + } else { + // Unhide: last active item, immediately before the first still-hidden item + insertAt = state.customItems.findIndex((it) => it.hidden === true); + if (insertAt < 0) insertAt = state.customItems.length; + } + state.customItems.splice(insertAt, 0, item); + + if (insertAt !== hideIndex) { + moveCustomItemExpanded(state, hideIndex, insertAt); + if (state.customItemEditorIndex === hideIndex) { + state.customItemEditorIndex = insertAt; + } else if (state.customItemEditorIndex != null) { + if (hideIndex < state.customItemEditorIndex && insertAt >= state.customItemEditorIndex) { + state.customItemEditorIndex -= 1; + } else if (hideIndex > state.customItemEditorIndex && insertAt <= state.customItemEditorIndex) { + state.customItemEditorIndex += 1; + } + } + } + + if (typeof onRefresh === 'function') onRefresh(root); + break; + } + case actions.moveLeft: { + const leftIndex = parseInt(el.dataset.itemIndex, 10); + if (Number.isNaN(leftIndex) || leftIndex <= 0) break; + collectCustomItemsFromForm(root, state, opts); + const swapWith = leftIndex - 1; + const tmp = state.customItems[leftIndex]; + state.customItems[leftIndex] = state.customItems[swapWith]; + state.customItems[swapWith] = tmp; + swapCustomItemExpanded(state, leftIndex, swapWith); + if (state.customItemEditorIndex === leftIndex) state.customItemEditorIndex = swapWith; + else if (state.customItemEditorIndex === swapWith) state.customItemEditorIndex = leftIndex; + if (!swapAdjacentCustomItemTiles(root, leftIndex, swapWith) && typeof onRefresh === 'function') { + onRefresh(root); + } + break; + } + case actions.moveRight: { + const rightIndex = parseInt(el.dataset.itemIndex, 10); + if (Number.isNaN(rightIndex) || rightIndex >= state.customItems.length - 1) break; + collectCustomItemsFromForm(root, state, opts); + const swapWith = rightIndex + 1; + const tmp = state.customItems[rightIndex]; + state.customItems[rightIndex] = state.customItems[swapWith]; + state.customItems[swapWith] = tmp; + swapCustomItemExpanded(state, rightIndex, swapWith); + if (state.customItemEditorIndex === rightIndex) state.customItemEditorIndex = swapWith; + else if (state.customItemEditorIndex === swapWith) state.customItemEditorIndex = rightIndex; + if (!swapAdjacentCustomItemTiles(root, rightIndex, swapWith) && typeof onRefresh === 'function') { + onRefresh(root); + } + break; + } default: break; } @@ -431,7 +613,10 @@ closeEditor: 'hsae-close-custom-item-editor', addItem: 'hsae-add-custom-item', removeItem: 'hsae-remove-custom-item', - toggleImages: 'hsae-toggle-custom-images' + toggleImages: 'hsae-toggle-custom-images', + toggleHide: 'hsae-toggle-custom-item-hide', + moveLeft: 'hsae-move-custom-item-left', + moveRight: 'hsae-move-custom-item-right' }, ...overrides }) diff --git a/configuration/homeScreenEditorProfiles.js b/configuration/homeScreenEditorProfiles.js index cf3a2b8..e1ca389 100644 --- a/configuration/homeScreenEditorProfiles.js +++ b/configuration/homeScreenEditorProfiles.js @@ -17,7 +17,7 @@ lockVisibility: true, allowGroupChange: false, allowItemSourceChange: false, - hideCustomItems: true + hideCustomItems: false }, postProcessing: { queryFields: ['limit'], @@ -25,7 +25,7 @@ lockVisibility: true, allowGroupChange: false, allowItemSourceChange: false, - hideCustomItems: true + hideCustomItems: false }, normal: { queryFields: ['limit', 'sortBy', 'sortOrder'], diff --git a/configuration/homeScreenSectionEditor.css b/configuration/homeScreenSectionEditor.css index 18988ca..17224af 100644 --- a/configuration/homeScreenSectionEditor.css +++ b/configuration/homeScreenSectionEditor.css @@ -407,13 +407,34 @@ html:not(.layout-mobile) [data-modal-id="kefin-homescreen-section-create-flow"] white-space: nowrap; } +[data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-tile.is-hidden .hsse-custom-item-tile-image, +[data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-tile.is-hidden .hsse-custom-item-tile-label { + opacity: 0.4; + filter: grayscale(0.35); +} + +[data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-actions { + display: flex; + align-items: center; + justify-content: center; + gap: 0.2em; +} + +[data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-action, [data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-trash { font-size: 0; padding: 0.3em; min-height: 0; + min-width: 0; line-height: 1; } +[data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-action:disabled { + opacity: 0.35; + cursor: default; +} + +[data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-action-icon, [data-modal-id="kefin-homescreen-section-create-flow"] .hsse-custom-item-trash-icon { font-size: 1.1rem; } diff --git a/configuration/homeScreenSectionEditor.js b/configuration/homeScreenSectionEditor.js index 73254e3..e6c72f0 100644 --- a/configuration/homeScreenSectionEditor.js +++ b/configuration/homeScreenSectionEditor.js @@ -164,6 +164,9 @@ } function createBlankCustomItem() { + if (window.KefinHomeScreenCustomItemsEditor?.createBlankCustomItem) { + return window.KefinHomeScreenCustomItemsEditor.createBlankCustomItem(); + } return { name: '', cardFooter: '', @@ -173,7 +176,8 @@ backdropUrl: '', squareUrl: '', bannerUrl: '', - logoUrl: '' + logoUrl: '', + hidden: false }; } @@ -186,7 +190,10 @@ closeEditor: 'wizard-close-custom-item-editor', addItem: 'wizard-add-custom-item', removeItem: 'wizard-remove-custom-item', - toggleImages: 'wizard-toggle-custom-images' + toggleImages: 'wizard-toggle-custom-images', + toggleHide: 'wizard-toggle-custom-item-hide', + moveLeft: 'wizard-move-custom-item-left', + moveRight: 'wizard-move-custom-item-right' } }); } @@ -240,6 +247,9 @@ } function buildStaticItemFromDraft(draft) { + if (window.KefinHomeScreenCustomItemsEditor?.buildStaticItemFromDraft) { + return window.KefinHomeScreenCustomItemsEditor.buildStaticItemFromDraft(draft); + } const name = draft.name?.trim(); const posterUrl = draft.posterUrl?.trim(); if (!name || !posterUrl) return null; @@ -251,11 +261,13 @@ if (value) provided[key] = value; }); - const item = { Name: name, Type: 'Folder' }; + const item = { Name: name, Type: draft.type || 'Folder' }; + if (draft.id) item.Id = draft.id; const cardUrl = draft.cardUrl?.trim(); if (cardUrl) item.cardUrl = cardUrl; const cardFooter = draft.cardFooter?.trim(); if (cardFooter) item.cardFooter = cardFooter; + if (draft.hidden === true) item.hidden = true; const keys = Object.keys(provided); if (keys.length === 1 && provided.posterUrl) { @@ -4277,7 +4289,10 @@ 'wizard-close-custom-item-editor', 'wizard-add-custom-item', 'wizard-remove-custom-item', - 'wizard-toggle-custom-images' + 'wizard-toggle-custom-images', + 'wizard-toggle-custom-item-hide', + 'wizard-move-custom-item-left', + 'wizard-move-custom-item-right' ]); if (wizardCustomActions.has(action) && window.KefinHomeScreenCustomItemsEditor) { window.KefinHomeScreenCustomItemsEditor.handleAction( diff --git a/scripts/cardBuilder.js b/scripts/cardBuilder.js index d89912a..7e981f5 100644 --- a/scripts/cardBuilder.js +++ b/scripts/cardBuilder.js @@ -1936,7 +1936,8 @@ const normalizeTemplate = (value) => (value || '').replace(/\$\{kefinTweaksRoot\}/g, kefinTweaksRoot).replace(/\$\{serverId\}/g, serverId); - return sectionConfig.items.map((item, index) => ({ + const visibleItems = (sectionConfig.items || []).filter((item) => item && item.hidden !== true); + return visibleItems.map((item, index) => ({ Name: item.Name, Id: item.Id || 'static-' + sectionConfig.id + '-' + index, Type: item.Type || 'Folder', diff --git a/scripts/sectionHelper.js b/scripts/sectionHelper.js index a91839f..5c12a55 100644 --- a/scripts/sectionHelper.js +++ b/scripts/sectionHelper.js @@ -245,7 +245,8 @@ .replace(/\$\{kefinTweaksRoot\}/g, kefinTweaksRoot) .replace(/\$\{serverId\}/g, serverId); - const normalizedItems = sectionConfig.items.map((item, index) => { + const visibleItems = sectionConfig.items.filter((item) => item && item.hidden !== true); + const normalizedItems = visibleItems.map((item, index) => { const posterUrl = normalizeTemplate(item.posterUrl); const thumbUrl = normalizeTemplate(item.thumbUrl); const squareUrl = normalizeTemplate(item.squareUrl);