add Keyboard Input, improve PopUp, improve general code

This commit is contained in:
E44
2025-11-07 12:15:58 +01:00
parent 10a09bc45e
commit 0bfe6371fd
11 changed files with 286 additions and 33 deletions
@@ -12,50 +12,90 @@
TrafficCone
} from 'lucide-svelte';
import Button from './Button.svelte';
import PopUp from './PopUp.svelte';
import type { PopupContent } from '../ts/types';
import KeyInput from './KeyInput.svelte';
let popup_content: PopupContent = $state({
open: false,
snippet: null,
title: '',
closable: true
});
function popup_close_function() {
popup_content.open = false;
}
const show_send_keys_popup = () => {
popup_content = {
open: true,
snippet: send_keys_popup,
title: 'Tastatur-Eingaben durchgeben',
title_icon: Keyboard,
closable: true
};
};
</script>
{#snippet send_keys_popup()}
<div>
<KeyInput />
</div>
<div class="flex flex-row justify-end gap-2">
<Button className="px-4 font-bold" click_function={popup_close_function}>Fertig</Button>
</div>
{/snippet}
<div class="grid grid-rows-[2.5rem_auto] bg-stone-800 rounded-2xl min-w-0">
<div class="text-xl font-bold pl-3 content-center bg-stone-700 rounded-t-2xl truncate min-w-0">
Bildschirme steuern
</div>
<div class="flex flex-col gap-2 p-2 overflow-auto">
<div class="relative flex flex-col gap-2 p-2 overflow-auto">
<div class="flex flex-row justify-between gap-2">
<div class="flex flex-col gap-2">
<div class="flex flex-row gap-2 w-70 justify-normal">
<Button title="Vorherige Folie (Pfeil nach Links)" className="px-7"
<div class="flex flex-row gap-2 w-75 justify-normal">
<Button title="Vorherige Folie (Pfeil nach Links)" className="px-9"
><ArrowBigLeft /></Button
>
<Button title="Nächste Folie (Pfeil nach Rechts)" className="px-7"
<Button title="Nächste Folie (Pfeil nach Rechts)" className="px-9"
><ArrowBigRight /></Button
>
</div>
<Button className="px-3 flex gap-3 w-70 justify-normal"
<Button className="px-3 flex gap-3 w-75 justify-normal"
><TextAlignStart /> Text anzeigen</Button
>
<Button className="px-3 flex gap-3 w-70 justify-normal"><Presentation />Blackout</Button>
<Button className="px-3 flex gap-3 w-75 justify-normal"><Presentation />Blackout</Button>
<div class="flex flex-row justify-normal">
<Button className="rounded-r-none pl-3 flex gap-3 grow w-60 justify-normal"
<Button className="rounded-r-none pl-3 flex gap-3 grow w-65 justify-normal"
><TrafficCone /> Fallback-Bild anzeigen</Button
>
<Button className="rounded-l-none flex grow-0 w-10"><ChevronDown /></Button>
</div>
<Button className="px-3 flex gap-3 w-70 justify-normal"
><Keyboard /> Tastatur-Inputs durchgeben</Button
<Button
className="px-3 flex gap-3 w-75 justify-normal"
click_function={show_send_keys_popup}><Keyboard /> Tastatur-Eingaben durchgeben</Button
>
</div>
<div class="flex flex-col gap-2 justify-between">
<div class="flex flex-col gap-2">
<Button className="px-3 flex gap-3 w-full xl:w-70 justify-normal"
<Button className="px-3 flex gap-3 w-full xl:w-75 justify-normal"
><Power /> PC hochfahren</Button
>
<Button className="px-3 flex gap-3 w-full xl:w-70 justify-normal"
<Button className="px-3 flex gap-3 w-full xl:w-75 justify-normal"
><PowerOff /> PC herunterfahren</Button
>
</div>
<Button className="px-3 flex gap-3 w-full xl:w-70 justify-normal"
<Button className="px-3 flex gap-3 w-full xl:w-75 justify-normal"
><SquareTerminal /> Shell-Befehl ausführen</Button
>
</div>
</div>
<PopUp
content={popup_content}
close_function={popup_close_function}
className="rounded-b-2xl"
snippet_container_class="overflow-hidden"
/>
</div>
</div>
@@ -10,6 +10,7 @@
import OnlineState from './OnlineState.svelte';
import type { Display, MenuOption } from '../ts/types';
import { is_selected, select, selected_display_ids } from '../ts/stores/select';
import { update_screenshot } from '../ts/stores/displays';
let { display, get_display_menu_options } = $props<{
display: Display;
@@ -29,6 +30,7 @@
} else {
$pinned_display_id = display.id;
}
update_screenshot(display.id);
e.stopPropagation();
}
</script>
@@ -102,7 +102,7 @@
<div class="flex flex-row gap-1">
<OnlineState
selected={false}
status={pinned_display?.status ?? ''}
status={pinned_display?.status ?? null}
className="flex items-center px-2"
/>
<Button
@@ -30,7 +30,12 @@
import RefreshPlay from './RefreshPlay.svelte';
import { get_file_size_display_string } from '../ts/utils';
import { open_file } from '../ts/api_handler';
import { displays, get_display_by_id, update_screenshot } from '../ts/stores/displays';
import {
displays,
get_display_by_id,
run_on_all_selected_displays,
update_screenshot
} from '../ts/stores/displays';
let { file } = $props<{ file: FolderElement }>();
@@ -97,13 +102,7 @@
change_file_path($current_file_path + file.name + '/');
} else {
const path_to_file = $current_file_path + file.name;
for (const display_id of $selected_display_ids) {
const ip = get_display_by_id(display_id, $displays)?.ip ?? null;
if (ip) {
await open_file(ip, path_to_file);
await update_screenshot(display_id);
}
}
await run_on_all_selected_displays(open_file, true, path_to_file);
}
}
</script>
@@ -0,0 +1,70 @@
<script lang="ts">
import { flip } from 'svelte/animate';
import { get_selectable_color_classes } from '../ts/stores/ui_behavior';
import key_map_json from './../../../../shared/keys.json';
import { fade } from 'svelte/transition';
import { selected_display_ids } from '../ts/stores/select';
import { displays, get_display_by_id, run_on_all_selected_displays } from '../ts/stores/displays';
import { send_keyboard_input } from '../ts/api_handler';
const bg = 'bg-stone-700';
const key_map: Record<string, string> = key_map_json as Record<string, string>;
let active = $state(false);
let last_keys: { id: number; key: string }[] = $state([]);
let el: HTMLDivElement;
function add_to_last_keys(name: string) {
const id = Date.now();
last_keys.push({ id, key: name });
setTimeout(() => {
last_keys = last_keys.filter((e) => e.id !== id);
}, 1500);
}
async function on_key_down(e: KeyboardEvent) {
if (!active) return;
const id = key_map[e.code];
if (!id) return;
e.preventDefault();
e.stopPropagation();
add_to_last_keys(e.code);
if (e.repeat) return;
await run_on_all_selected_displays(send_keyboard_input, true, id);
}
</script>
<div
role="textbox"
tabindex="0"
bind:this={el}
onclick={() => {
if (active) {
el.blur();
} else {
el.focus();
active = true;
}
}}
onblur={() => (active = false)}
onkeydown={on_key_down}
class="relative flex justify-center items-center h-15 w-full cursor-pointer rounded-xl transition-colors duration-200 select-none {get_selectable_color_classes(
active,
{
bg: true,
hover: true,
active: true,
text: true
}
)}"
>
{active ? 'Erfassung aktiv' : 'Hier für Erfassung klicken'}
<div class="absolute top-full left-0 ml-1 mt-0.5 flex flex-col-reverse text-sm text-stone-400">
{#each last_keys as key (key.id)}
<span animate:flip={{ duration: 200 }} in:fade={{ duration: 200 }} out:fade={{ duration: 500 }} >{key.key}</span>
{/each}
</div>
</div>
+8 -6
View File
@@ -5,9 +5,11 @@
import type { PopupContent } from '../ts/types';
import { fade } from 'svelte/transition';
let { content, close_function } = $props<{
let { content, close_function, className = '', snippet_container_class = '' } = $props<{
content: PopupContent;
close_function: () => void;
className?: string;
snippet_container_class?: string;
}>();
function try_to_close() {
@@ -31,7 +33,7 @@
<!-- svelte-ignore a11y_no_static_element_interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="absolute inset-0 backdrop-blur bg-white/10 flex justify-center items-center"
class="absolute inset-0 backdrop-blur flex justify-center items-center {className}"
onclick={try_to_close}
transition:fade={{ duration: 100 }}
>
@@ -42,12 +44,12 @@
onclick={(e) => e.stopPropagation()}
>
<div
class="text-2xl font-bold bg-stone-700 p-1.5 flex flex-row justify-between gap-6 w-full"
class="font-bold bg-stone-700 p-1.5 flex flex-row justify-between gap-8 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 ?? ''}">
<div class="flex flex-row flex-1 gap-3 pl-2 py-1 items-center grow whitespace-nowrap min-w-0 flex-shrink-0 text-lg {content.title_class ?? ''}">
{#if content.title_icon}
{@const Icon = content.title_icon}
<Icon strokeWidth="2.8" class="flex-shrink-0" />
<Icon strokeWidth="2" class="flex-shrink-0" />
{/if}
<div class="flex-shrink-0">
{content.title}
@@ -61,7 +63,7 @@
{/if}
</div>
</div>
<div class="p-2 min-h-0 overflow-auto flex flex-col gap-2">
<div class="p-2 min-h-0 overflow-auto flex flex-col gap-2 {snippet_container_class}">
{@render content.snippet(content.snippet_arg)}
</div>
</div>