full suport for models and hotloading Plugins
This commit is contained in:
@@ -3382,10 +3382,11 @@ a.deletelink {
|
||||
gap: 0.5rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
border-radius: 6px;
|
||||
background: var(--md-sys-color-surface-container-low, #f7f7f9);
|
||||
background: var(--md-sys-color-surface-variant, #45475a);
|
||||
color: var(--md-sys-color-on-surface, #cdd6f4);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.mods-item:hover { background: var(--md-sys-color-surface-container, #efeff3); }
|
||||
.mods-item:hover { background: var(--md-sys-color-surface2, #585b70); }
|
||||
.mods-name { font-weight: 600; }
|
||||
.mods-file { color: var(--md-sys-color-on-surface-variant, #777); font-size: 0.78rem; }
|
||||
.mods-badge {
|
||||
@@ -3432,3 +3433,54 @@ a.deletelink {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Plugins tab */
|
||||
.plugins-warning {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
background: #fff4e0;
|
||||
border: 1px solid #f0c878;
|
||||
color: #7a4d00;
|
||||
padding: 0.7rem 0.9rem;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 0.9rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.plugins-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
margin-bottom: 0.9rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.plugins-toggle .switch { position: relative; display: inline-block; width: 42px; height: 24px; flex: 0 0 auto; }
|
||||
.plugins-toggle .switch input { opacity: 0; width: 0; height: 0; }
|
||||
.plugins-toggle .slider {
|
||||
position: absolute; cursor: pointer; inset: 0;
|
||||
background: #cbd5e1; border-radius: 999px; transition: background 0.15s;
|
||||
}
|
||||
.plugins-toggle .slider:before {
|
||||
content: ''; position: absolute; height: 18px; width: 18px; left: 3px; top: 3px;
|
||||
background: #fff; border-radius: 50%; transition: transform 0.15s;
|
||||
}
|
||||
.plugins-toggle .switch input:checked + .slider { background: #059669; }
|
||||
.plugins-toggle .switch input:checked + .slider:before { transform: translateX(18px); }
|
||||
.plugins-list {
|
||||
list-style: none; margin: 0; padding: 0;
|
||||
display: flex; flex-direction: column; gap: 0.25rem;
|
||||
}
|
||||
.plugins-list li {
|
||||
display: flex; align-items: center; gap: 0.5rem;
|
||||
padding: 0.35rem 0.6rem; border-radius: 6px;
|
||||
background: var(--md-sys-color-surface-variant, #45475a);
|
||||
color: var(--md-sys-color-on-surface, #cdd6f4);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.plugins-name { font-weight: 600; color: inherit; }
|
||||
.plugins-badge.autoload {
|
||||
margin-left: auto;
|
||||
border-radius: 999px; background: #e0e7ff; color: #3730a3;
|
||||
padding: 0.1rem 0.5rem; font-size: 0.68rem; font-weight: 600; text-transform: uppercase;
|
||||
}
|
||||
.plugins-size { color: var(--md-sys-color-on-surface-variant, #6b7280); font-size: 0.78rem; }
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
const member = btn.dataset.member;
|
||||
const name = btn.dataset.name || member;
|
||||
const modelFormat = btn.dataset.modelFormat || '.geo.json';
|
||||
const slug = btn.dataset.projectSlug || '';
|
||||
const opts = { baseUrl: btn.dataset.baseUrl, vanillaBaseUrl: btn.dataset.vanillaBaseUrl, defaultTexture: btn.dataset.defaultTexture || null };
|
||||
if (!member || !opts.baseUrl || busy) return;
|
||||
busy = true;
|
||||
@@ -223,6 +224,16 @@
|
||||
busy = false;
|
||||
return;
|
||||
}
|
||||
// Pack plugins to hotload (autoload.txt), unless the user opted out.
|
||||
const noHotload = slug && localStorage.getItem('packs:no-hotload:' + slug) === '1';
|
||||
if (!noHotload && btn.dataset.plugins) {
|
||||
try {
|
||||
const members = JSON.parse(btn.dataset.plugins);
|
||||
msg.plugins = members.map(m => ({ member: m, url: assetUrl(opts.baseUrl, m) }));
|
||||
} catch (e) {
|
||||
msg.plugins = [];
|
||||
}
|
||||
}
|
||||
if (EMBEDDED_FORMATS.indexOf(modelFormat) !== -1) {
|
||||
// Textures baked into the file — hand it to Blockbench as-is.
|
||||
msg.modelFile = { format: modelFormat, content: await fetchModelText(member, opts.baseUrl) };
|
||||
|
||||
@@ -103,9 +103,27 @@
|
||||
}
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
await hotloadPackPlugins(msg.plugins);
|
||||
notify('model-open', { name: name });
|
||||
}
|
||||
|
||||
// Hotload plugins bundled with the pack (served via pack_asset). A failing
|
||||
// plugin is reported but never blocks the model preview.
|
||||
async function hotloadPackPlugins(plugins) {
|
||||
for (const p of (plugins || [])) {
|
||||
if (!p || !p.url || !p.member) continue;
|
||||
try {
|
||||
const code = await (await fetch(p.url, { headers: { 'Accept': 'text/javascript' } })).text();
|
||||
if (!code || code.length < 20) continue;
|
||||
await new Plugin().loadFromFile({ path: p.member, content: code }, true);
|
||||
notify('plugin-hotloaded', { name: p.member });
|
||||
} catch (e) {
|
||||
console.error('packs pack plugin hotload failed', p.member, e);
|
||||
notify('plugin-error', { error: 'Failed to load plugin ' + p.member });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('message', (e) => {
|
||||
if (!e.data || e.data.type !== 'packs-open-model') return;
|
||||
openModel(e.data).then(
|
||||
|
||||
Reference in New Issue
Block a user