ShyyTAUI/src/lib/components/notifications/Popup.svelte
Luna ca7560d10a fix tournament name being not updatable
also make the saved tourney settings popup disappear faster
2025-09-27 04:29:59 +02:00

332 lines
No EOL
9.6 KiB
Svelte

<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import { fade } from 'svelte/transition';
// Define color presets
const colorPresets = {
primary: 'var(--accent-glow)',
secondary: 'var(--text-secondary)',
success: '#4CAF50',
warning: '#FFC107',
error: '#F44336',
info: '#2196F3',
default: 'var(--text-primary)'
};
type ButtonType = 'primary' | 'secondary' | 'text' | 'outlined';
type ColorPreset = keyof typeof colorPresets;
interface ButtonConfig {
text: string;
type: ButtonType;
href?: string;
color?: ColorPreset;
icon?: string;
action?: () => void;
}
// Props
export let open = false;
export let message: string = '';
export let icon: string = '';
export let iconColor: ColorPreset = 'primary';
export let buttons: ButtonConfig[] = [];
export let customImage: string = '';
export let autoClose: number = 1500; // 0 means no auto close
// Event dispatcher
const dispatch = createEventDispatcher();
// Close the notification
function close() {
open = false;
dispatch('close');
}
// Handle button click
function handleButtonClick(button: ButtonConfig) {
if (button.action) {
button.action();
}
if (!button.href) {
close();
}
}
// Auto close functionality
onMount(() => {
if (autoClose > 0 && open) {
const timer = setTimeout(() => {
close();
}, autoClose);
return () => {
clearTimeout(timer);
};
}
});
// Get color from preset or return the input if not a preset
function getColor(colorName: ColorPreset): string {
return colorPresets[colorName] || colorName;
}
// Get button class based on type
function getButtonClass(type: ButtonType): string {
switch(type) {
case 'primary':
return 'btn-primary';
case 'secondary':
return 'btn-secondary';
case 'text':
return 'btn-text';
case 'outlined':
return 'btn-outlined';
default:
return 'btn-primary';
}
}
</script>
{#if open}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="notification-overlay" transition:fade={{ duration: 200 }} on:click={close}>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div class="notification-container" on:click|stopPropagation>
<div class="notification-content">
{#if customImage}
<div class="custom-image">
{#if customImage.endsWith('.svg')}
{@html customImage}
{:else}
<!-- svelte-ignore a11y-img-redundant-alt -->
<img src={customImage} alt="Notification image" />
{/if}
</div>
{:else if icon}
<div class="notification-icon" style="color: {getColor(iconColor)}">
<span class="material-icons">{icon}</span>
</div>
{/if}
<div class="notification-message">
{message}
</div>
{#if buttons.length > 0}
<div class="notification-actions">
{#each buttons as button}
{#if button.href}
<a
href={button.href}
class="notification-button {getButtonClass(button.type)}"
style={button.color ? `--button-color: ${getColor(button.color)};` : ''}
>
{#if button.icon}
<span class="material-icons" style={button.color ? `color: ${getColor(button.color)};` : ''}>
{button.icon}
</span>
{/if}
<span>{button.text}</span>
</a>
{:else}
<button
class="notification-button {getButtonClass(button.type)}"
style={button.color ? `--button-color: ${getColor(button.color)};` : ''}
on:click={() => handleButtonClick(button)}
>
{#if button.icon}
<span class="material-icons" style={button.color ? `color: ${getColor(button.color)};` : ''}>
{button.icon}
</span>
{/if}
<span>{button.text}</span>
</button>
{/if}
{/each}
</div>
{/if}
</div>
</div>
</div>
{/if}
<style>
.notification-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(3px);
}
.notification-container {
background-color: var(--bg-secondary);
border-radius: 8px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
width: 90%;
max-width: 500px;
border: 1px solid var(--border-color);
overflow: hidden;
animation: popup 0.3s ease forwards;
}
@keyframes popup {
0% { transform: scale(0.9); opacity: 0; }
100% { transform: scale(1); opacity: 1; }
}
.notification-content {
padding: 2rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
}
.notification-icon {
font-size: 3rem;
display: flex;
justify-content: center;
align-items: center;
}
.notification-icon .material-icons {
font-size: 3.5rem;
text-shadow: 0 0 10px var(--accent-glow);
}
.custom-image {
max-width: 120px;
margin-bottom: 1rem;
}
.custom-image img {
width: 100%;
height: auto;
}
.notification-message {
text-align: center;
font-size: 1.25rem;
color: var(--text-primary);
line-height: 1.6;
}
.notification-actions {
display: flex;
gap: 1rem;
justify-content: center;
margin-top: 1rem;
flex-wrap: wrap;
}
.notification-button {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
border-radius: 4px;
font-weight: 600;
font-size: 1rem;
transition: all 0.3s ease;
cursor: pointer;
text-decoration: none;
justify-content: center;
--button-color: var(--accent-color);
}
.notification-button .material-icons {
font-size: 1.25rem;
}
.btn-primary {
background-color: var(--button-color, var(--accent-color));
color: white;
border: none;
}
.btn-primary:hover {
background-color: var(--accent-hover);
box-shadow: 0 0 15px var(--accent-glow);
}
.btn-secondary {
background-color: transparent;
color: var(--button-color, var(--accent-color));
border: 1px solid var(--button-color, var(--accent-color));
}
.btn-secondary:hover {
background-color: rgba(var(--accent-color-rgb), 0.1);
}
.btn-text {
background-color: transparent;
color: var(--button-color, var(--accent-color));
border: none;
padding: 0.75rem 1rem;
}
.btn-text:hover {
background-color: rgba(var(--accent-color-rgb), 0.1);
}
.btn-outlined {
background-color: transparent;
color: var(--button-color, var(--accent-color));
border: 1px solid var(--button-color, var(--accent-color));
position: relative;
overflow: hidden;
}
.btn-outlined::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 3px;
background: linear-gradient(90deg, transparent, var(--button-color, var(--accent-color)), transparent);
transform: translateX(-100%);
transition: transform 0.3s ease;
opacity: 0;
}
.btn-outlined:hover {
text-shadow: 0 0 8px var(--accent-glow);
}
.btn-outlined:hover::after {
transform: translateX(0);
opacity: 1;
box-shadow: 0 0 15px var(--accent-glow);
}
@media (max-width: 480px) {
.notification-content {
padding: 1.5rem;
}
.notification-message {
font-size: 1rem;
}
.notification-actions {
flex-direction: column;
width: 100%;
}
.notification-button {
width: 100%;
}
}
</style>