Templates #1
@ -2,12 +2,16 @@
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window';
|
||||
import { onMount } from 'svelte';
|
||||
import { addTemplateFile } from '$lib/file_utils';
|
||||
import Popup from '$lib/components/Popup.svelte';
|
||||
let dragging = $state(false);
|
||||
let hasBlend = $state(false);
|
||||
let dropzoneEl = $state(null);
|
||||
|
||||
let { version } = $props();
|
||||
|
||||
let successPopup;
|
||||
let errorPopup;
|
||||
|
||||
onMount(() => {
|
||||
const win = getCurrentWindow();
|
||||
let unlisten = () => {};
|
||||
@ -47,9 +51,14 @@
|
||||
const blendFiles = payload.paths.filter((p) => p.endsWith('.blend'));
|
||||
if (blendFiles.length > 0) {
|
||||
console.log('Dropped Blender files:', blendFiles);
|
||||
blendFiles.forEach((file) => {
|
||||
blendFiles.forEach(async (file) => {
|
||||
if (version) {
|
||||
addTemplateFile(version, file);
|
||||
const result = await addTemplateFile(version, file);
|
||||
if (result.success) {
|
||||
successPopup.pop(result.message, 3000);
|
||||
} else {
|
||||
errorPopup.pop(result.message, 4000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -66,6 +75,9 @@
|
||||
|
||||
<div class="dropzone" class:dragging bind:this={dropzoneEl}>Drop Blender Files</div>
|
||||
|
||||
<Popup bind:this={successPopup} type="confirm" />
|
||||
<Popup bind:this={errorPopup} type="error" />
|
||||
|
||||
<style>
|
||||
.dropzone {
|
||||
height: 3rem;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
<script>
|
||||
import { fade, fly } from 'svelte/transition';
|
||||
|
||||
let { content = '', type = 'confirm' } = $props();
|
||||
let { type = 'confirm' } = $props();
|
||||
let open = $state(false);
|
||||
let message = $state('');
|
||||
|
||||
export function pop(resetTimeout = 0) {
|
||||
export function pop(msg = '', resetTimeout = 0) {
|
||||
message = msg;
|
||||
open = true;
|
||||
if (resetTimeout > 0) {
|
||||
setTimeout(() => {
|
||||
@ -17,7 +19,7 @@
|
||||
{#if open}
|
||||
<div in:fly={{ duration: 200, y: 100 }} out:fade class="popup {type}">
|
||||
<div class="popup-content">
|
||||
<p>{content}</p>
|
||||
<p>{message}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@ -35,4 +37,7 @@
|
||||
.confirm {
|
||||
background-color: var(--light-accent);
|
||||
}
|
||||
.error {
|
||||
background-color: var(--accent);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
async function handleDownload() {
|
||||
let result = await downloadBlenderVersion(selectedLink);
|
||||
if (result.success) {
|
||||
popup?.pop(2000);
|
||||
popup?.pop('Blender ' + selectedLink.version + ' has been installed', 2000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,8 +29,7 @@
|
||||
let popup = $state();
|
||||
</script>
|
||||
|
||||
<Popup bind:this={popup} content={'Blender ' + selectedLink.version + ' has been installed'}
|
||||
></Popup>
|
||||
<Popup bind:this={popup}></Popup>
|
||||
<div class="download" class:full-width={downloading || installed}>
|
||||
<div class="selectVersion {downloading}">
|
||||
<select class:disabled={downloading && !installed} bind:value={linkIndex}>
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
import { deleteTemplate } from '$lib/library';
|
||||
|
||||
import { launchBlenderVersion } from '$lib/library';
|
||||
import { notify } from '$lib/notification.js';
|
||||
let { template, version } = $props();
|
||||
let templateName = $derived(
|
||||
template
|
||||
@ -22,13 +23,18 @@
|
||||
*/
|
||||
async function handleDelete(template) {
|
||||
const prompt = await show({
|
||||
title: 'Delete',
|
||||
message: `This will remove Blender ${version.version} and all associated files from your system.`,
|
||||
title: 'Delete Template',
|
||||
message: `This will delete the "${templateName}" template.`,
|
||||
buttons: ['Cancel', 'Continue'],
|
||||
type: 'warning'
|
||||
});
|
||||
if (prompt == 'Continue') {
|
||||
deleteTemplate(version, template);
|
||||
const result = await deleteTemplate(version, template);
|
||||
if (result.success) {
|
||||
notify(result.message, 3000);
|
||||
} else {
|
||||
notify(result.message, 4000);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script>
|
||||
import Popup from '$lib/components/Popup.svelte';
|
||||
import {
|
||||
deleteVersion,
|
||||
launchBlenderVersion,
|
||||
@ -12,9 +11,9 @@
|
||||
import MenuItem from '$lib/components/MenuItem.svelte';
|
||||
|
||||
import { show } from '$lib/components/Dialog.svelte';
|
||||
import { notify } from '$lib/notification.js';
|
||||
|
||||
let { version, selectedVersion } = $props();
|
||||
let popup = $state();
|
||||
|
||||
let selected = $derived(version.version === selectedVersion?.version);
|
||||
|
||||
@ -26,7 +25,12 @@
|
||||
type: 'warning'
|
||||
});
|
||||
if (prompt == 'Continue') {
|
||||
deleteVersion(version);
|
||||
const result = await deleteVersion(version);
|
||||
if (result.success) {
|
||||
notify(result.message, 3000);
|
||||
} else {
|
||||
notify(result.message, 4000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,13 +42,11 @@
|
||||
type: 'info'
|
||||
});
|
||||
if (prompt == 'Continue') {
|
||||
popup.pop(1500);
|
||||
notify('Version ' + version.version + ' is now the default on your system', 1500);
|
||||
registerVersion(version);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Popup bind:this={popup} content="Version {version.version} is now the default on your system" />
|
||||
<div
|
||||
role="button"
|
||||
tabindex="0"
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
basename as pathBasename,
|
||||
dirname as pathDirname
|
||||
} from '@tauri-apps/api/path';
|
||||
import { stat, mkdir, readDir, copyFile, rename, remove } from '@tauri-apps/plugin-fs';
|
||||
import { stat, mkdir, readDir, copyFile, rename, remove, exists } from '@tauri-apps/plugin-fs';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import baseicon from '$lib/assets/baseicon.png';
|
||||
import europa from '$lib/assets/fonts/Europa-Mono-Medium.otf';
|
||||
@ -124,19 +124,25 @@ export async function addTemplateFile(version, filePath) {
|
||||
const newFileName = await pathBasename(filePath);
|
||||
const templateName = newFileName.replace(/\.blend$/i, '');
|
||||
const newTemplatePath = await join(await getTemplatesDir(version), templateName);
|
||||
await ensureDirectory(newTemplatePath)
|
||||
|
||||
// Check for duplicate template name
|
||||
if (await exists(newTemplatePath)) {
|
||||
return { success: false, message: `Template "${templateName}" already exists` };
|
||||
}
|
||||
|
||||
const newTemplateFile = await join(newTemplatePath, 'startup.blend');
|
||||
await ensureDirectory(newTemplatePath);
|
||||
|
||||
try {
|
||||
await copyFile(filePath, newTemplateFile);
|
||||
} catch (error) {
|
||||
console.error('Error adding template file:', error);
|
||||
return;
|
||||
return { success: false, message: `Failed to add template: ${error.message || error}` };
|
||||
}
|
||||
|
||||
await getInstalledVersions();
|
||||
|
||||
console.log('adding ', filePath, ' to ', newTemplateFile);
|
||||
return { success: true, message: `Template "${templateName}" added` };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -255,8 +255,10 @@ export async function deleteTemplate(version, template) {
|
||||
try {
|
||||
await removeTemplate(templatePath);
|
||||
await getInstalledVersions();
|
||||
return { success: true, message: `Template "${template}" deleted` };
|
||||
} catch (error) {
|
||||
console.error('Failed to delete template', error);
|
||||
return { success: false, message: `Failed to delete template: ${error.message || error}` };
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,9 +284,10 @@ export async function deleteVersion(version) {
|
||||
installedVersionsStore.set(filteredVersions);
|
||||
|
||||
console.log(`Successfully deleted version ${version.version}`);
|
||||
return { success: true, message: `Blender ${version.version} deleted` };
|
||||
} catch (error) {
|
||||
console.error(`Failed to delete version ${version.version}:`, error);
|
||||
throw error;
|
||||
return { success: false, message: `Failed to delete Blender ${version.version}: ${error.message || error}` };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
src/lib/notification.js
Normal file
12
src/lib/notification.js
Normal file
@ -0,0 +1,12 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const notification = writable(null);
|
||||
|
||||
/**
|
||||
* Show a notification popup.
|
||||
* @param {string} message - The message to display
|
||||
* @param {number} [timeout=3000] - Auto-dismiss timeout in milliseconds
|
||||
*/
|
||||
export function notify(message, timeout = 3000) {
|
||||
notification.set({ message, timeout });
|
||||
}
|
||||
@ -18,6 +18,7 @@
|
||||
import Popup from '$lib/components/Popup.svelte';
|
||||
import Dialog from '$lib/components/Dialog.svelte';
|
||||
import Splash from '$lib/components/Splash.svelte';
|
||||
import { notification } from '$lib/notification.js';
|
||||
|
||||
// states
|
||||
let fadeInSettings = { duration: 100 };
|
||||
@ -27,10 +28,17 @@
|
||||
let installedVersions = $state([]);
|
||||
let downloadTasks = $state([]);
|
||||
let settings = $state();
|
||||
let notificationPopup;
|
||||
let initialized = $state(false);
|
||||
let version = $state('');
|
||||
let loadingState = $state('loading'); // load, update, initialized
|
||||
|
||||
notification.subscribe((n) => {
|
||||
if (n) {
|
||||
notificationPopup?.pop(n.message, n.timeout);
|
||||
}
|
||||
});
|
||||
|
||||
async function initStoresListeners() {
|
||||
currentSettings.subscribe((value) => {
|
||||
settings = value;
|
||||
@ -68,7 +76,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<Popup content="Are you sure you want to delete this file?" type="confirm" />
|
||||
<Popup bind:this={notificationPopup} />
|
||||
<Dialog />
|
||||
|
||||
<div id="main">
|
||||
@ -194,7 +202,7 @@
|
||||
#tabcontent {
|
||||
background-color: var(--light);
|
||||
box-sizing: border-box;
|
||||
height: calc(100vh - 5rem);
|
||||
height: calc(100vh - 3rem);
|
||||
padding: 1rem;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user