FEAT: Reworked pop up notifications across all events

This commit is contained in:
valerio 2026-07-25 19:07:19 +02:00
parent 1cecec5a97
commit b1e3644e9d
9 changed files with 77 additions and 24 deletions

View File

@ -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;

View File

@ -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>

View File

@ -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}>

View File

@ -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>

View File

@ -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"

View File

@ -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` };
}
/**

View File

@ -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
View 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 });
}

View File

@ -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%;
}