add new monitor popup finished

This commit is contained in:
E44
2025-11-03 14:18:49 +01:00
parent e7903bde09
commit f31a118fb6
6 changed files with 296 additions and 51 deletions
+54 -36
View File
@@ -1,51 +1,69 @@
<script lang="ts">
import type { X } from 'lucide-svelte';
import { X } from 'lucide-svelte';
import { onDestroy, onMount } from 'svelte';
import Button from './Button.svelte';
import type { PopupContent } from '../ts/types';
import { fade } from 'svelte/transition';
let {
children,
title,
title_class = '',
title_icon,
closable = true,
close_function = null
} = $props<{
children: any;
title: string;
title_class?: string;
title_icon: typeof X;
closable?: boolean;
close_function?: () => void | null;
let { content, close_function } = $props<{
content: PopupContent;
close_function: () => void;
}>();
// onMount(() => {
// const handler = (e: KeyboardEvent) => {
// // if (e.key === 'Escape') dispatch('close');
// };
// window.addEventListener('keydown', handler);
// onDestroy(() => window.removeEventListener('keydown', handler));
// });
function try_to_close() {
if (!content.closable || !content.open) return;
close_function();
}
function handleKeydown(e: KeyboardEvent) {
if (e.key === 'Escape') {
try_to_close();
}
}
onMount(() => {
window.addEventListener('keydown', handleKeydown);
return () => window.removeEventListener('keydown', handleKeydown);
});
</script>
<div class="absolute inset-0 backdrop-blur bg-white/10 flex justify-center items-center">
{#if content.open}
<!-- svelte-ignore a11y_no_static_element_interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="bg-stone-800 rounded-2xl min-w-[40%] min-h-[30%] max-w-[80%] max-h-[80%] flex flex-col overflow-hidden shadow-2xl/30"
class="absolute inset-0 backdrop-blur bg-white/10 flex justify-center items-center"
onclick={try_to_close}
transition:fade={{ duration: 100 }}
>
<!-- svelte-ignore a11y_no_static_element_interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="text-2xl font-bold bg-stone-700 {title_class} px-4 py-2 flex flex-row justify-between"
class="bg-stone-800 rounded-2xl min-w-[30%] min-h-[30%] max-w-[80%] max-h-[80%] flex flex-col shadow-2xl/60 overflow-hidden"
onclick={(e) => e.stopPropagation()}
>
<div>
{title}
<div
class="text-2xl font-bold bg-stone-700 p-1.5 flex flex-row justify-between gap-6 w-full"
>
<div class="flex flex-row flex-1 gap-4 pl-2 py-1 items-center grow whitespace-nowrap min-w-0 flex-shrink-0 {content.title_class ?? ''}">
{#if content.title_icon}
{@const Icon = content.title_icon}
<Icon strokeWidth="2.8" class="flex-shrink-0" />
{/if}
<div class="flex-shrink-0">
{content.title}
</div>
</div>
<div class="flex aspect-square flex-shrink-0">
{#if content.closable}
<Button className="aspect-square !p-1.5" click_function={try_to_close}>
<X />
</Button>
{/if}
</div>
</div>
<div>
{#if title_icon}
{@const Icon = title_icon}
<Icon class="size-full" />
{/if}
<div class="p-2 min-h-0 overflow-auto flex flex-col gap-2">
{@render content.snippet()}
</div>
</div>
<div class="px-4 py-2 min-h-0 overflow-auto">
{@render children()}
</div>
</div>
</div>
{/if}
@@ -0,0 +1,70 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { get_shifted_color } from '../ts/stores/ui_behavior';
import { onMount } from 'svelte';
let {
current_value = $bindable(),
current_valid = $bindable(),
className = '',
bg = 'bg-stone-750',
title,
placeholder = '',
is_valid_function = null
} = $props<{
current_value: string;
current_valid: boolean;
className?: string;
bg?: string;
title: string;
placeholder?: string;
is_valid_function?: ((input: string) => [boolean, string]) | null;
}>();
let focus_bg = get_shifted_color(bg, 100);
let focussed = $state(false);
let current_info = $state('');
function validate_input() {
if (!is_valid_function) return;
[current_valid, current_info] = is_valid_function(current_value.trim());
}
function get_highlighting_string(): string {
if (!is_valid_function) return '';
if (current_valid) {
return 'focus:inset-ring-2 focus:inset-ring-green-400';
} else {
return 'inset-ring-2 inset-ring-red-400';
}
}
onMount(() => {
validate_input();
});
</script>
<div class="flex flex-col {className}">
<div class="flex flex-row justify-between text-sm px-1">
<div class="text-stone-400">
{title}:
</div>
{#if is_valid_function && focussed}
<div class={current_valid ? "text-green-400" : "text-red-400"} transition:fade={{ duration: 100 }}>
{current_info}
</div>
{/if}
</div>
<input
bind:value={current_value}
type="text"
oninput={validate_input}
onfocus={() => {
focussed = true;
}}
onfocusout={() => {
focussed = false;
}}
class="{bg} focus:{focus_bg} outline-none py-2 px-3 rounded-xl transition-all duration-100 {get_highlighting_string()}"
{placeholder}
/>
</div>