Fixing problems
This commit is contained in:
@@ -40,10 +40,10 @@
|
|||||||
editMode = modes[(idx + 1) % modes.length];
|
editMode = modes[(idx + 1) % modes.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
let htmlContainer: HTMLDivElement;
|
let htmlContainer = $state<HTMLDivElement>(undefined!);
|
||||||
let cssContainer: HTMLDivElement;
|
let cssContainer = $state<HTMLDivElement>(undefined!);
|
||||||
let sharedContainer: HTMLDivElement;
|
let sharedContainer = $state<HTMLDivElement>(undefined!);
|
||||||
let appContainer: HTMLDivElement;
|
let appContainer = $state<HTMLDivElement>(undefined!);
|
||||||
|
|
||||||
let htmlEditor: EditorView | null = null;
|
let htmlEditor: EditorView | null = null;
|
||||||
let cssEditor: EditorView | null = null;
|
let cssEditor: EditorView | null = null;
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Square, Type, Image, Music, Video, Globe } from 'lucide-svelte';
|
import { Square, Type, Image, Music, Video, Globe } from 'lucide-svelte';
|
||||||
import { state } from './state.svelte';
|
import { state as appState } from './state.svelte';
|
||||||
|
|
||||||
let locked = $derived(state.locked);
|
let locked = $derived(appState.locked);
|
||||||
|
|
||||||
let imageInput: HTMLInputElement;
|
let imageInput = $state<HTMLInputElement>(undefined!);
|
||||||
let soundInput: HTMLInputElement;
|
let soundInput = $state<HTMLInputElement>(undefined!);
|
||||||
let videoInput: HTMLInputElement;
|
let videoInput = $state<HTMLInputElement>(undefined!);
|
||||||
|
|
||||||
function getSpawnPosition() {
|
function getSpawnPosition() {
|
||||||
return {
|
return {
|
||||||
x: state.snap(-state.viewport.x / state.viewport.zoom + 400),
|
x: appState.snap(-appState.viewport.x / appState.viewport.zoom + 400),
|
||||||
y: state.snap(-state.viewport.y / state.viewport.zoom + 300)
|
y: appState.snap(-appState.viewport.y / appState.viewport.zoom + 300)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTile() {
|
function addTile() {
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
const pos = getSpawnPosition();
|
const pos = getSpawnPosition();
|
||||||
state.addItem({
|
appState.addItem({
|
||||||
id,
|
id,
|
||||||
html: '',
|
html: '',
|
||||||
css: '',
|
css: '',
|
||||||
@@ -27,15 +27,15 @@
|
|||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
zIndex: state.maxZIndex + 1
|
zIndex: appState.maxZIndex + 1
|
||||||
});
|
});
|
||||||
state.select(id);
|
appState.select(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addText() {
|
function addText() {
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
const pos = getSpawnPosition();
|
const pos = getSpawnPosition();
|
||||||
state.addItem({
|
appState.addItem({
|
||||||
id,
|
id,
|
||||||
html: '<p>Text</p>',
|
html: '<p>Text</p>',
|
||||||
css: `p {
|
css: `p {
|
||||||
@@ -48,9 +48,9 @@
|
|||||||
width: 200,
|
width: 200,
|
||||||
height: 50,
|
height: 50,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
zIndex: state.maxZIndex + 1
|
zIndex: appState.maxZIndex + 1
|
||||||
});
|
});
|
||||||
state.select(id);
|
appState.select(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addEmbed() {
|
function addEmbed() {
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
if (!url) return;
|
if (!url) return;
|
||||||
const id = crypto.randomUUID();
|
const id = crypto.randomUUID();
|
||||||
const pos = getSpawnPosition();
|
const pos = getSpawnPosition();
|
||||||
state.addItem({
|
appState.addItem({
|
||||||
id,
|
id,
|
||||||
html: `<iframe src="${url}" frameborder="0" allowfullscreen></iframe>`,
|
html: `<iframe src="${url}" frameborder="0" allowfullscreen></iframe>`,
|
||||||
css: `iframe {
|
css: `iframe {
|
||||||
@@ -71,9 +71,9 @@
|
|||||||
width: 640,
|
width: 640,
|
||||||
height: 480,
|
height: 480,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
zIndex: state.maxZIndex + 1
|
zIndex: appState.maxZIndex + 1
|
||||||
});
|
});
|
||||||
state.select(id);
|
appState.select(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleImageChange(e: Event) {
|
function handleImageChange(e: Event) {
|
||||||
@@ -105,8 +105,8 @@
|
|||||||
|
|
||||||
const img = document.createElement('img');
|
const img = document.createElement('img');
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
state.addAsset(assetId, { blob: file, url, filename: file.name });
|
appState.addAsset(assetId, { blob: file, url, filename: file.name });
|
||||||
state.addItem({
|
appState.addItem({
|
||||||
id,
|
id,
|
||||||
assetId,
|
assetId,
|
||||||
html: `<img src="${url}" alt="" />`,
|
html: `<img src="${url}" alt="" />`,
|
||||||
@@ -120,9 +120,9 @@
|
|||||||
width: img.naturalWidth,
|
width: img.naturalWidth,
|
||||||
height: img.naturalHeight,
|
height: img.naturalHeight,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
zIndex: state.maxZIndex + 1
|
zIndex: appState.maxZIndex + 1
|
||||||
});
|
});
|
||||||
state.select(id);
|
appState.select(id);
|
||||||
};
|
};
|
||||||
img.src = url;
|
img.src = url;
|
||||||
}
|
}
|
||||||
@@ -133,8 +133,8 @@
|
|||||||
const url = URL.createObjectURL(file);
|
const url = URL.createObjectURL(file);
|
||||||
const pos = getSpawnPosition();
|
const pos = getSpawnPosition();
|
||||||
|
|
||||||
state.addAsset(assetId, { blob: file, url, filename: file.name });
|
appState.addAsset(assetId, { blob: file, url, filename: file.name });
|
||||||
state.addItem({
|
appState.addItem({
|
||||||
id,
|
id,
|
||||||
assetId,
|
assetId,
|
||||||
html: `<audio src="${url}" controls></audio>`,
|
html: `<audio src="${url}" controls></audio>`,
|
||||||
@@ -146,9 +146,9 @@
|
|||||||
width: 300,
|
width: 300,
|
||||||
height: 54,
|
height: 54,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
zIndex: state.maxZIndex + 1
|
zIndex: appState.maxZIndex + 1
|
||||||
});
|
});
|
||||||
state.select(id);
|
appState.select(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addVideoItem(file: File) {
|
function addVideoItem(file: File) {
|
||||||
@@ -159,8 +159,8 @@
|
|||||||
|
|
||||||
const video = document.createElement('video');
|
const video = document.createElement('video');
|
||||||
video.onloadedmetadata = () => {
|
video.onloadedmetadata = () => {
|
||||||
state.addAsset(assetId, { blob: file, url, filename: file.name });
|
appState.addAsset(assetId, { blob: file, url, filename: file.name });
|
||||||
state.addItem({
|
appState.addItem({
|
||||||
id,
|
id,
|
||||||
assetId,
|
assetId,
|
||||||
html: `<video src="${url}" controls></video>`,
|
html: `<video src="${url}" controls></video>`,
|
||||||
@@ -173,9 +173,9 @@
|
|||||||
width: video.videoWidth || 640,
|
width: video.videoWidth || 640,
|
||||||
height: video.videoHeight || 360,
|
height: video.videoHeight || 360,
|
||||||
rotation: 0,
|
rotation: 0,
|
||||||
zIndex: state.maxZIndex + 1
|
zIndex: appState.maxZIndex + 1
|
||||||
});
|
});
|
||||||
state.select(id);
|
appState.select(id);
|
||||||
};
|
};
|
||||||
video.src = url;
|
video.src = url;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export async function importBoard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.load(manifest, assets);
|
await state.load(manifest, assets);
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {
|
return {
|
||||||
@@ -175,8 +175,7 @@ export async function mergeBoard(
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
state.addAssets(newAssets);
|
await state.mergeData(newAssets, newItems);
|
||||||
state.addItems(newItems);
|
|
||||||
|
|
||||||
return { success: true, itemCount: newItems.length };
|
return { success: true, itemCount: newItems.length };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -93,22 +93,30 @@ function createState() {
|
|||||||
: 0,
|
: 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
async function save() {
|
async function saveNow(): Promise<void> {
|
||||||
|
if (saveTimeout) {
|
||||||
|
clearTimeout(saveTimeout);
|
||||||
|
saveTimeout = null;
|
||||||
|
}
|
||||||
|
const storedAssets: Record<string, StoredAsset> = {};
|
||||||
|
for (const [id, asset] of Object.entries(assets)) {
|
||||||
|
storedAssets[id] = {
|
||||||
|
dataUrl: await blobToDataUrl(asset.blob),
|
||||||
|
filename: asset.filename,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const stored: StoredState = { manifest, assets: storedAssets };
|
||||||
|
try {
|
||||||
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(stored));
|
||||||
|
} catch {
|
||||||
|
// localStorage full or unavailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
if (saveTimeout) clearTimeout(saveTimeout);
|
if (saveTimeout) clearTimeout(saveTimeout);
|
||||||
saveTimeout = setTimeout(async () => {
|
saveTimeout = setTimeout(() => {
|
||||||
const storedAssets: Record<string, StoredAsset> = {};
|
saveNow();
|
||||||
for (const [id, asset] of Object.entries(assets)) {
|
|
||||||
storedAssets[id] = {
|
|
||||||
dataUrl: await blobToDataUrl(asset.blob),
|
|
||||||
filename: asset.filename,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const stored: StoredState = { manifest, assets: storedAssets };
|
|
||||||
try {
|
|
||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(stored));
|
|
||||||
} catch {
|
|
||||||
// localStorage full or unavailable
|
|
||||||
}
|
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +189,12 @@ function createState() {
|
|||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function mergeData(newAssets: AssetStore, newItems: Item[]): Promise<void> {
|
||||||
|
Object.assign(assets, newAssets);
|
||||||
|
manifest.items.push(...newItems);
|
||||||
|
await saveNow();
|
||||||
|
}
|
||||||
|
|
||||||
function getItem(id: string): Item | undefined {
|
function getItem(id: string): Item | undefined {
|
||||||
return manifest.items.find((i) => i.id === id);
|
return manifest.items.find((i) => i.id === id);
|
||||||
}
|
}
|
||||||
@@ -417,8 +431,16 @@ function createState() {
|
|||||||
localStorage.removeItem(STORAGE_KEY);
|
localStorage.removeItem(STORAGE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
function load(newManifest: Manifest, newAssets: AssetStore) {
|
async function load(newManifest: Manifest, newAssets: AssetStore): Promise<void> {
|
||||||
Object.values(assets).forEach((a) => URL.revokeObjectURL(a.url));
|
Object.values(assets).forEach((a) => URL.revokeObjectURL(a.url));
|
||||||
|
|
||||||
|
for (const item of newManifest.items) {
|
||||||
|
if (item.assetId && newAssets[item.assetId]) {
|
||||||
|
const newUrl = newAssets[item.assetId].url;
|
||||||
|
item.html = item.html.replace(/src="[^"]*"/g, `src="${newUrl}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
manifest = newManifest;
|
manifest = newManifest;
|
||||||
assets = newAssets;
|
assets = newAssets;
|
||||||
viewport = { x: 0, y: 0, zoom: 1 };
|
viewport = { x: 0, y: 0, zoom: 1 };
|
||||||
@@ -426,7 +448,7 @@ function createState() {
|
|||||||
editingId = null;
|
editingId = null;
|
||||||
editingGlobal = false;
|
editingGlobal = false;
|
||||||
focusedId = null;
|
focusedId = null;
|
||||||
save();
|
await saveNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
restore();
|
restore();
|
||||||
@@ -468,6 +490,7 @@ function createState() {
|
|||||||
removeItem,
|
removeItem,
|
||||||
addAsset,
|
addAsset,
|
||||||
addAssets,
|
addAssets,
|
||||||
|
mergeData,
|
||||||
getItem,
|
getItem,
|
||||||
select,
|
select,
|
||||||
toggleSelection,
|
toggleSelection,
|
||||||
|
|||||||
@@ -4,4 +4,7 @@ import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [svelte()],
|
plugins: [svelte()],
|
||||||
|
build: {
|
||||||
|
chunkSizeWarningLimit: 1000,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user