Skip to content

Commit d333877

Browse files
committed
fix(store): 关闭按钮不响应 + overlay 外HTML替换改为内HTML更新
1 parent 44f313e commit d333877

4 files changed

Lines changed: 117 additions & 66 deletions

File tree

dist/skins-pro.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/editor/events.ts

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ function bindSkinStoreOpen(host: EditorHost): void {
209209
likes: skinStats[th.id]?.liked ?? 0,
210210
userLiked: isSkinLiked(th.id),
211211
}));
212-
merged.sort((a, b) => Number(!!b.hasUpdate) - Number(!!a.hasUpdate));
212+
merged.sort((a, b) => (Number(!!b.hasUpdate) - Number(!!a.hasUpdate)) || ((b.downloads ?? 0) - (a.downloads ?? 0)));
213213
const hasMore = merged.length > 20;
214214
host.onChange({ skinStore: { open: true, loading: false, error: '', themes: merged, searchQuery: '', hasMore, displayedCount: 20 } });
215215
} catch (err) {
@@ -237,6 +237,22 @@ function bindSkinStoreOpen(host: EditorHost): void {
237237
}
238238

239239
function bindSkinStoreActionButtons(host: EditorHost): void {
240+
host.root.querySelectorAll('[data-store-overlay]').forEach(overlay => {
241+
overlay.addEventListener('click', (e) => {
242+
if (e.target === overlay) {
243+
host.onChange({ skinStore: { ...host.state.skinStore, open: false } });
244+
host.renderSkinStoreOnly();
245+
}
246+
});
247+
});
248+
249+
host.root.querySelectorAll('[data-store-close]').forEach(btn => {
250+
btn.addEventListener('click', () => {
251+
host.onChange({ skinStore: { ...host.state.skinStore, open: false } });
252+
host.renderSkinStoreOnly();
253+
});
254+
});
255+
240256
host.root.querySelectorAll<HTMLElement>('[data-store-remove]').forEach(btn => {
241257
btn.addEventListener('click', () => {
242258
const skin = btn.getAttribute('data-store-remove');
@@ -268,21 +284,24 @@ function bindSkinStoreActionButtons(host: EditorHost): void {
268284
});
269285
});
270286

271-
const loadMoreBtn = host.root.querySelector<HTMLElement>('[data-store-load-more]');
272-
if (loadMoreBtn) {
273-
loadMoreBtn.addEventListener('click', () => {
274-
const q = (host.state.skinStore.searchQuery || '').trim();
275-
const filtered = q
276-
? host.state.skinStore.themes.filter(th => {
277-
const tokens = q.toLowerCase().split(/\s+/).filter(Boolean);
278-
const haystack = [th.id, th.name || '', th.author || '', ...(th.tags || []), th.description || ''].join(' ').toLowerCase();
279-
return tokens.every(t => haystack.includes(t));
280-
})
281-
: host.state.skinStore.themes;
282-
const next = host.state.skinStore.displayedCount + 20;
283-
const hasMore = next < filtered.length;
284-
host.onChange({ skinStore: { ...host.state.skinStore, displayedCount: next, hasMore } });
285-
host.renderSkinStoreOnly();
287+
const storeGrid = host.root.querySelector<HTMLElement>('.store-grid');
288+
if (storeGrid) {
289+
storeGrid.addEventListener('scroll', () => {
290+
if (!host.state.skinStore.hasMore) return;
291+
if (storeGrid.scrollTop + storeGrid.clientHeight >= storeGrid.scrollHeight - 60) {
292+
const q = (host.state.skinStore.searchQuery || '').trim();
293+
const filtered = q
294+
? host.state.skinStore.themes.filter(th => {
295+
const tokens = q.toLowerCase().split(/\s+/).filter(Boolean);
296+
const haystack = [th.id, th.name || '', th.author || '', ...(th.tags || []), th.description || ''].join(' ').toLowerCase();
297+
return tokens.every(t => haystack.includes(t));
298+
})
299+
: host.state.skinStore.themes;
300+
const next = host.state.skinStore.displayedCount + 20;
301+
const hasMore = next < filtered.length;
302+
host.onChange({ skinStore: { ...host.state.skinStore, displayedCount: next, hasMore } });
303+
host.renderSkinStoreOnly();
304+
}
286305
});
287306
}
288307

src/editor/skin-store.ts

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -93,28 +93,55 @@ export function renderSkinStore(
9393
config: DashboardConfigRecord,
9494
language: Language,
9595
): string {
96-
if (!state.open) return '';
96+
const displayStyle = state.open ? 'display:flex' : 'display:none';
9797

98-
let content: string;
98+
if (!state.open) {
99+
return `
100+
<div class="nav-overlay" data-store-overlay style="${displayStyle}">
101+
<div class="nav-dialog" style="max-width:1200px;width:95vw">
102+
<h3>${t(language, 'editorSkinStore')}</h3>
103+
<div data-store-body></div>
104+
</div>
105+
</div>`;
106+
}
107+
108+
return `
109+
<div class="nav-overlay" data-store-overlay style="${displayStyle}">
110+
<div class="nav-dialog" style="max-width:1200px;width:95vw">
111+
<h3>${t(language, 'editorSkinStore')} <span class="store-dependency" style="font-size:0.7em;font-weight:400;color:var(--sp-text-muted,#888)">${linkifyDep(t(language, 'editorSkinStoreDependency'), language)}</span></h3>
112+
<div data-store-body>
113+
${renderSkinStoreBody(state, config, language)}
114+
</div>
115+
</div>
116+
</div>
117+
`;
118+
}
119+
120+
export function renderSkinStoreBody(
121+
state: SkinStoreState,
122+
config: DashboardConfigRecord,
123+
language: Language,
124+
): string {
99125
if (state.loading) {
100-
content = `<p style="text-align:center;padding:40px 0;color:var(--sp-text-muted,#888)">${t(language, 'loadingQuote')}</p>`;
101-
} else if (state.error) {
102-
content = `<p style="text-align:center;padding:40px 0;color:var(--sp-error,#e44)">${t(language, 'editorSkinStoreLoadFailed')}</p>`;
103-
} else {
104-
const downloaded: string[] = config.downloaded_skins || [];
105-
const filtered = filterThemes(state.themes, state.searchQuery);
106-
const displayedCount = state.displayedCount || BATCH_SIZE;
107-
const visible = filtered.slice(0, displayedCount);
126+
return `<p style="text-align:center;padding:40px 0;color:var(--sp-text-muted,#888)">${t(language, 'loadingQuote')}</p>`;
127+
}
128+
if (state.error) {
129+
return `<p style="text-align:center;padding:40px 0;color:var(--sp-error,#e44)">${t(language, 'editorSkinStoreLoadFailed')}</p>`;
130+
}
131+
const downloaded: string[] = config.downloaded_skins || [];
132+
const filtered = filterThemes(state.themes, state.searchQuery);
133+
const displayedCount = state.displayedCount || BATCH_SIZE;
134+
const visible = filtered.slice(0, displayedCount);
108135

109-
const cards = visible.map(theme => {
110-
const installed = downloaded.includes(theme.id);
111-
const dlCount = theme.downloads ?? '-';
112-
const likeCount = theme.likes ?? 0;
113-
const likedClass = theme.userLiked ? ' liked' : '';
114-
const tagsHtml = theme.tags?.length
115-
? `<div class="store-tags">${theme.tags.slice(0, 4).map(tag => `<span class="store-tag">${tag}</span>`).join('')}</div>`
116-
: '';
117-
return `
136+
const cards = visible.map(theme => {
137+
const installed = downloaded.includes(theme.id);
138+
const dlCount = theme.downloads ?? '-';
139+
const likeCount = theme.likes ?? 0;
140+
const likedClass = theme.userLiked ? ' liked' : '';
141+
const tagsHtml = theme.tags?.length
142+
? `<div class="store-tags">${theme.tags.slice(0, 4).map(tag => `<span class="store-tag">${tag}</span>`).join('')}</div>`
143+
: '';
144+
return `
118145
<div class="store-card ${installed ? 'store-installed' : ''}" data-store-theme="${theme.id}">
119146
<img src="${CDN_STORE}/${theme.thumbnail}" alt="${theme.name}" class="store-thumb" loading="lazy">
120147
<div class="store-info">
@@ -134,37 +161,27 @@ export function renderSkinStore(
134161
}
135162
</div>
136163
</div>`;
137-
});
164+
});
138165

139-
const remaining = Math.max(0, filtered.length - displayedCount);
140-
const loader = remaining > 0
141-
? `<div class="store-load-more" data-store-load-more style="text-align:center;padding:16px;color:var(--sp-accent,#78a8b8);cursor:pointer;font-size:var(--sp-font-xs,13px);border-top:1px solid var(--sp-border-muted,var(--divider-color,rgba(0,0,0,0.08)));margin-top:12px">
142-
${t(language, 'showAll')} (${remaining} ${t(language, 'devices')})
143-
</div>`
144-
: '';
166+
const remaining = Math.max(0, filtered.length - displayedCount);
167+
const loader = remaining > 0
168+
? `<div class="store-load-indicator" style="text-align:center;padding:12px;font-size:var(--sp-font-2xs,11px);color:var(--sp-text-muted,#888)">
169+
${t(language, 'showAll')} (${remaining})
170+
</div>`
171+
: '';
145172

146-
const resultLabel = filtered.length > 0
147-
? `<div class="store-result-count" style="font-size:var(--sp-font-3xs,10px);color:var(--sp-text-muted,#888);margin-bottom:8px;padding:0 4px">${displayedCount} / ${filtered.length}</div>`
148-
: '';
173+
const resultLabel = filtered.length > 0
174+
? `<div class="store-result-count" style="font-size:var(--sp-font-3xs,10px);color:var(--sp-text-muted,#888);margin-bottom:8px;padding:0 4px">${displayedCount} / ${filtered.length}</div>`
175+
: '';
149176

150-
content = `
177+
return `
151178
<input type="text" class="store-search" data-store-search placeholder="${t(language, 'editorSkinStoreSearch')}" value="${state.searchQuery || ''}" style="width:100%;box-sizing:border-box;padding:10px 14px;border-radius:var(--sp-radius-pill,999px);border:1px solid var(--sp-border-muted,var(--divider-color,rgba(0,0,0,0.12)));background:var(--sp-device-bg,rgba(128,128,128,0.06));color:var(--sp-text-main,inherit);font:inherit;font-size:var(--sp-font-xs,14px);outline:none;margin-bottom:var(--sp-space-md,16px);">
152179
${resultLabel}
153-
<div class="store-grid">${cards}</div>
154-
${loader}`;
155-
}
156-
157-
return `
158-
<div class="nav-overlay" data-store-overlay style="display:flex">
159-
<div class="nav-dialog" style="max-width:1200px;width:95vw">
160-
<h3>${t(language, 'editorSkinStore')} <span class="store-dependency" style="font-size:0.7em;font-weight:400;color:var(--sp-text-muted,#888)">${linkifyDep(t(language, 'editorSkinStoreDependency'), language)}</span></h3>
161-
${content}
162-
<div class="nav-dialog-actions">
163-
<button class="nav-cancel" data-store-close>${t(language, 'editorSkinStoreClose')}</button>
164-
</div>
165-
</div>
166-
</div>
167-
`;
180+
<div class="store-grid">${cards.join('')}</div>
181+
${loader}
182+
<div class="nav-dialog-actions">
183+
<button class="nav-cancel" data-store-close>${t(language, 'editorSkinStoreClose')}</button>
184+
</div>`;
168185
}
169186

170187
export async function fetchSkinThemes(): Promise<SkinStoreTheme[]> {

src/skins-pro-card-editor.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { assetHref, getTranslate, normalizeLanguage } from './utils';
33
import { type DashboardConfigRecord } from './editor/config';
44
import { renderEditorTemplate } from './editor/template';
55
import { bindEditorEvents, bindSkinStoreActions, type EditorState } from './editor/events';
6-
import { renderSkinStore } from './editor/skin-store';
6+
import { renderSkinStoreBody } from './editor/skin-store';
77

88
export class SkinsProCardEditor extends HTMLElement {
99
private _state: EditorState = {
@@ -91,10 +91,20 @@ export class SkinsProCardEditor extends HTMLElement {
9191

9292
public renderSkinStoreOnly(): void {
9393
if (!this.shadowRoot) return;
94-
const storeOverlay = this.shadowRoot.querySelector('[data-store-overlay]');
95-
if (!storeOverlay) return;
94+
const storeOverlay = this.shadowRoot.querySelector('[data-store-overlay]') as HTMLElement;
95+
const storeBody = this.shadowRoot.querySelector('[data-store-body]') as HTMLElement;
96+
const oldGrid = this.shadowRoot.querySelector('.store-grid');
97+
const savedScroll = oldGrid ? oldGrid.scrollTop : 0;
9698
const language = this._currentLanguage();
97-
storeOverlay.outerHTML = renderSkinStore(this._state.skinStore, this._state.config, language);
99+
const state = this._state.skinStore;
100+
101+
if (storeOverlay) {
102+
storeOverlay.style.display = state.open ? 'flex' : 'none';
103+
}
104+
105+
if (storeBody) {
106+
storeBody.innerHTML = state.open ? renderSkinStoreBody(state, this._state.config, language) : '';
107+
}
98108

99109
bindSkinStoreActions(this.shadowRoot, {
100110
el: this,
@@ -104,6 +114,11 @@ export class SkinsProCardEditor extends HTMLElement {
104114
reload: () => this.render(),
105115
renderSkinStoreOnly: () => this.renderSkinStoreOnly(),
106116
});
117+
118+
const newGrid = this.shadowRoot.querySelector('.store-grid');
119+
if (newGrid && savedScroll > 0) {
120+
newGrid.scrollTop = savedScroll;
121+
}
107122
}
108123
}
109124

0 commit comments

Comments
 (0)