mirror of
https://codeberg.org/PLG-Development/PLG-MuDiCS
synced 2026-07-06 00:47:09 +00:00
refactor(control): move components from /routes to /components and /svgs
This commit is contained in:
@@ -1,126 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { dragHandleZone, TRIGGERS } from 'svelte-dnd-action';
|
||||
import {
|
||||
dnd_flip_duration_ms,
|
||||
get_selectable_color_classes,
|
||||
is_display_drag,
|
||||
is_group_drag
|
||||
} from '$lib/ts/stores/ui_behavior';
|
||||
import { cubicOut } from 'svelte/easing';
|
||||
import { flip } from 'svelte/animate';
|
||||
import DisplayObject from './DisplayObject.svelte';
|
||||
import {
|
||||
all_displays_of_group_selected,
|
||||
get_display_ids_in_group,
|
||||
select_all_of_group,
|
||||
set_new_display_order
|
||||
} from '$lib/ts/stores/displays';
|
||||
import DNDGrip from '$lib/components/DNDGrip.svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
import type { MenuOption } from '$lib/ts/types';
|
||||
import { selected_display_ids } from '$lib/ts/stores/select';
|
||||
import { liveQuery, type Observable } from 'dexie';
|
||||
|
||||
let {
|
||||
display_group_id,
|
||||
get_display_menu_options,
|
||||
close_pinned_display
|
||||
}: {
|
||||
display_group_id: string;
|
||||
get_display_menu_options: (display_id: string) => MenuOption[];
|
||||
close_pinned_display: () => void;
|
||||
} = $props();
|
||||
|
||||
let all_selected: Observable<boolean> | undefined = $state();
|
||||
$effect(() => {
|
||||
const sdi = $selected_display_ids;
|
||||
all_selected = liveQuery(() => all_displays_of_group_selected(display_group_id, sdi));
|
||||
});
|
||||
let display_ids_in_group = liveQuery(() => get_display_ids_in_group(display_group_id));
|
||||
let hovering_selectable = $state(false);
|
||||
|
||||
async function select_all_of_this_group() {
|
||||
const new_value = !($all_selected || false);
|
||||
await select_all_of_group(display_group_id, new_value);
|
||||
}
|
||||
|
||||
async function handle_consider(e: CustomEvent) {
|
||||
const { items, info } = e.detail;
|
||||
|
||||
if (items.length !== 1 && info.trigger === TRIGGERS.DRAG_STARTED) {
|
||||
$is_display_drag = true;
|
||||
// add_empty_display_group();
|
||||
}
|
||||
await set_new_display_order(items);
|
||||
}
|
||||
|
||||
async function handle_finalize(e: CustomEvent) {
|
||||
$is_display_drag = false;
|
||||
await set_new_display_order(e.detail.items);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
transition:fade={{ duration: 100 }}
|
||||
class="{get_selectable_color_classes(
|
||||
$all_selected || false,
|
||||
{
|
||||
bg: true,
|
||||
hover: hovering_selectable,
|
||||
active: hovering_selectable,
|
||||
text: true
|
||||
},
|
||||
-150,
|
||||
-50
|
||||
)} transition-colors duration-200 rounded-2xl flex flex-row cursor-pointer"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col min-w-0 pl-2 py-2 gap-2 w-full"
|
||||
use:dragHandleZone={{
|
||||
items: $display_ids_in_group || [],
|
||||
type: 'item',
|
||||
flipDurationMs: dnd_flip_duration_ms,
|
||||
dropTargetStyle: { outline: 'none' }
|
||||
}}
|
||||
onconsider={handle_consider}
|
||||
onfinalize={handle_finalize}
|
||||
>
|
||||
{#each $display_ids_in_group || [] as display (display.id)}
|
||||
<!-- Each Group -->
|
||||
<section
|
||||
animate:flip={{ duration: $is_group_drag ? 0 : dnd_flip_duration_ms, easing: cubicOut }}
|
||||
class="outline-none"
|
||||
role="figure"
|
||||
>
|
||||
<DisplayObject {display} {get_display_menu_options} {close_pinned_display} />
|
||||
</section>
|
||||
{/each}
|
||||
|
||||
{#if ($display_ids_in_group || []).length === 0}
|
||||
<div class="min-h-10 h-full w-full pl-2 py-2 flex justify-center items-center">
|
||||
Hier in leere neue Gruppe ablegen
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center justify-center px-2"
|
||||
onclick={select_all_of_this_group}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
onkeydown={async (e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') await select_all_of_this_group();
|
||||
}}
|
||||
onmouseenter={() => (hovering_selectable = true)}
|
||||
onmouseleave={() => (hovering_selectable = false)}
|
||||
>
|
||||
<DNDGrip
|
||||
bg={get_selectable_color_classes(
|
||||
$all_selected || false,
|
||||
{
|
||||
bg: true
|
||||
},
|
||||
-150
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,143 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import {
|
||||
current_height,
|
||||
get_selectable_color_classes,
|
||||
pinned_display_id
|
||||
} from '$lib/ts/stores/ui_behavior';
|
||||
import DNDGrip from '$lib/components/DNDGrip.svelte';
|
||||
import { Menu, Pin, PinOff, VideoOff } from 'lucide-svelte';
|
||||
import OnlineState from './OnlineState.svelte';
|
||||
import type { Display, MenuOption } from '$lib/ts/types';
|
||||
import { is_selected, select, selected_display_ids } from '$lib/ts/stores/select';
|
||||
import { screenshot_loop } from '$lib/ts/stores/displays';
|
||||
import { change_file_path, current_file_path } from '$lib/ts/stores/files';
|
||||
|
||||
let {
|
||||
display,
|
||||
get_display_menu_options,
|
||||
close_pinned_display
|
||||
}: {
|
||||
display: Display;
|
||||
get_display_menu_options: (display_id: string) => MenuOption[];
|
||||
close_pinned_display: () => void;
|
||||
} = $props();
|
||||
|
||||
let hovering_unselectable = $state(false);
|
||||
|
||||
async function onclick(e: Event) {
|
||||
e.stopPropagation();
|
||||
select(selected_display_ids, display.id, 'toggle');
|
||||
|
||||
// force file view update
|
||||
await change_file_path($current_file_path);
|
||||
}
|
||||
|
||||
async function on_preview_click(e: MouseEvent) {
|
||||
if ($pinned_display_id === display.id) {
|
||||
close_pinned_display();
|
||||
} else {
|
||||
$pinned_display_id = display.id;
|
||||
}
|
||||
await screenshot_loop(display.id);
|
||||
e.stopPropagation();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
data-testid="display"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
onkeydown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') onclick(e);
|
||||
}}
|
||||
{onclick}
|
||||
class="p-1 {get_selectable_color_classes(is_selected(display.id, $selected_display_ids), {
|
||||
bg: true,
|
||||
hover: true,
|
||||
active: !hovering_unselectable,
|
||||
text: true
|
||||
})} rounded-xl flex flex-row justify-between h-{$current_height.display} transition-colors duration-100 gap-2 cursor-pointer w-full text-stone-200"
|
||||
>
|
||||
<div class="flex flex-row gap-4 min-w-0 flex-1">
|
||||
<!-- Left Preview Screen -->
|
||||
<button
|
||||
class="group relative aspect-video bg-stone-800 h-full rounded-lg overflow-hidden cursor-pointer text-stone-200 transition-colors duration-200"
|
||||
onmouseenter={() => (hovering_unselectable = true)}
|
||||
onmouseleave={() => (hovering_unselectable = false)}
|
||||
onclick={on_preview_click}
|
||||
>
|
||||
<div class="flex h-full w-full items-center justify-center">
|
||||
{#if $pinned_display_id === display.id}
|
||||
<div class="size-[50%]">
|
||||
<Pin class="size-full" />
|
||||
</div>
|
||||
{:else if display.preview.url}
|
||||
<img src={display.preview.url} alt="preview" class="w-full object-cover bg-black" />
|
||||
{:else}
|
||||
<!-- No Signal -->
|
||||
<div class="size-full bg-black flex justify-center items-center">
|
||||
<VideoOff class="size-[30%]" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Hover Effect -->
|
||||
<span
|
||||
class="pointer-events-none absolute inset-0 {$pinned_display_id === display.id
|
||||
? 'bg-stone-700'
|
||||
: 'bg-stone-700/70'} opacity-0 transition-opacity duration-200 flex items-center justify-center group-hover:opacity-100"
|
||||
>
|
||||
{#if $pinned_display_id === display.id}
|
||||
<PinOff class="size-[50%]" aria-hidden="true" />
|
||||
{:else}
|
||||
<Pin class="size-[50%]" aria-hidden="true" />
|
||||
{/if}
|
||||
</span>
|
||||
</button>
|
||||
<!-- Middle Text Block -->
|
||||
<div
|
||||
class="h-full flex flex-col justify-center gap-1 select-none
|
||||
min-w-0 basis-0 flex-1"
|
||||
>
|
||||
<div class="text-xl font-bold truncate w-full" title={display.name}>
|
||||
{display.name}
|
||||
</div>
|
||||
|
||||
<OnlineState
|
||||
selected={is_selected(display.id, $selected_display_ids)}
|
||||
status={display.status}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Right Controls -->
|
||||
<div class="flex flex-row h-full items-center gap-2 pr-3">
|
||||
<DNDGrip
|
||||
bg={get_selectable_color_classes(is_selected(display.id, $selected_display_ids), {
|
||||
bg: true
|
||||
})}
|
||||
/>
|
||||
|
||||
<div
|
||||
role="figure"
|
||||
onmouseenter={() => (hovering_unselectable = true)}
|
||||
onmouseleave={() => (hovering_unselectable = false)}
|
||||
>
|
||||
<Button
|
||||
bg="bg-transparent"
|
||||
hover_bg={get_selectable_color_classes(is_selected(display.id, $selected_display_ids), {
|
||||
bg: true
|
||||
})}
|
||||
active_bg={get_selectable_color_classes(is_selected(display.id, $selected_display_ids), {
|
||||
bg: true
|
||||
})}
|
||||
click_function={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
menu_options={get_display_menu_options(display.id)}
|
||||
>
|
||||
<Menu />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -19,13 +19,13 @@
|
||||
} from '$lib/ts/stores/ui_behavior';
|
||||
import { type Display, type DisplayGroup, type MenuOption } from '$lib/ts/types';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import OnlineState from './OnlineState.svelte';
|
||||
import OnlineState from '../lib/components/OnlineState.svelte';
|
||||
import { cubicOut } from 'svelte/easing';
|
||||
import { Menu, Pencil, PinOff, Settings, Trash2, VideoOff, ZoomIn, ZoomOut } from 'lucide-svelte';
|
||||
import { selected_display_ids } from '$lib/ts/stores/select';
|
||||
import { dragHandleZone } from 'svelte-dnd-action';
|
||||
import { flip } from 'svelte/animate';
|
||||
import DisplayGroupObject from './DisplayGroupObject.svelte';
|
||||
import DisplayGroupObject from '../lib/components/DisplayGroupObject.svelte';
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes';
|
||||
import HighlightedText from '$lib/components/HighlightedText.svelte';
|
||||
import { liveQuery, type Observable } from 'dexie';
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
create_folder_on_all_selected_displays
|
||||
} from '$lib/ts/stores/files';
|
||||
import { slide } from 'svelte/transition';
|
||||
import InodeElement from './InodeElement.svelte';
|
||||
import InodeElement from '../lib/components/InodeElement.svelte';
|
||||
import PopUp from '$lib/components/PopUp.svelte';
|
||||
import { get_file_primary_key, type Inode, type PopupContent } from '$lib/ts/types';
|
||||
import TextInput from '$lib/components/TextInput.svelte';
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ArrowRight, Ban, FileIcon, Folder, Play } from 'lucide-svelte';
|
||||
import {
|
||||
current_height,
|
||||
get_selectable_color_classes,
|
||||
get_shifted_color
|
||||
} from '$lib/ts/stores/ui_behavior';
|
||||
import Button from '$lib/components/Button.svelte';
|
||||
import { supported_file_type_icon, type Inode, get_file_primary_key } from '$lib/ts/types';
|
||||
|
||||
import {
|
||||
is_selected,
|
||||
select,
|
||||
selected_display_ids,
|
||||
selected_file_ids
|
||||
} from '$lib/ts/stores/select';
|
||||
import {
|
||||
change_file_path,
|
||||
current_file_path,
|
||||
get_missing_colliding_display_ids
|
||||
} from '$lib/ts/stores/files';
|
||||
import RefreshPlay from './RefreshPlay.svelte';
|
||||
import { get_file_size_display_string, get_file_type } from '$lib/ts/utils';
|
||||
import { open_file } from '$lib/ts/api_handler';
|
||||
import { run_on_all_selected_displays } from '$lib/ts/stores/displays';
|
||||
import { get_thumbnail_url } from '$lib/ts/stores/thumbnails';
|
||||
import { liveQuery, type Observable } from 'dexie';
|
||||
|
||||
let { file, not_interactable = false }: { file: Inode; not_interactable?: boolean } = $props();
|
||||
|
||||
let missing_colliding_displays_ids:
|
||||
| Observable<{ missing: string[]; colliding: string[] }>
|
||||
| undefined = $state();
|
||||
$effect(() => {
|
||||
const s = $selected_file_ids;
|
||||
missing_colliding_displays_ids = liveQuery(() => get_missing_colliding_display_ids(file, s));
|
||||
});
|
||||
let thumbnail_url = liveQuery(() => get_thumbnail_url(file));
|
||||
|
||||
const is_folder = file.type === 'inode/directory';
|
||||
|
||||
function get_created_string(date_object: Date | null, full_string = false) {
|
||||
if (!date_object) {
|
||||
return full_string ? 'Verschiedene Daten auf verschiedenen Bildschirmen' : 'versch.';
|
||||
}
|
||||
|
||||
if (full_string) {
|
||||
return (
|
||||
get_formated_date_string(date_object, true) + ' ' + get_formated_time_string(date_object)
|
||||
);
|
||||
} else if (date_object.toDateString() === new Date().toDateString()) {
|
||||
return get_formated_time_string(date_object);
|
||||
} else {
|
||||
return get_formated_date_string(date_object);
|
||||
}
|
||||
}
|
||||
|
||||
function get_formated_time_string(date_object: Date) {
|
||||
return `${date_object.getHours().toString().padStart(2, '0')}:${date_object.getMinutes().toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function get_formated_date_string(date_object: Date, full_year = false) {
|
||||
return `${date_object.getDate().toString().padStart(2, '0')}.${(date_object.getMonth() + 1).toString().padStart(2, '0')}.${date_object
|
||||
.getFullYear()
|
||||
.toString()
|
||||
.slice(full_year ? 0 : 2)}`;
|
||||
}
|
||||
|
||||
function get_grayed_out_text_color_strings(is_selected: boolean): string {
|
||||
if (not_interactable) return 'text-stone-400';
|
||||
const color = is_selected ? 'text-stone-600' : 'text-stone-400';
|
||||
const factor = is_selected ? -1 : 1;
|
||||
return `${color} group-hover:${get_shifted_color(color, factor * 100)} group-active:${get_shifted_color(color, factor * 150)}`;
|
||||
}
|
||||
|
||||
function get_grayed_out_border_color_strings(is_selected: boolean): string {
|
||||
if (not_interactable) return 'border-stone-550';
|
||||
const color = is_selected ? 'border-stone-450' : 'border-stone-550';
|
||||
const factor = is_selected ? 1 : 1;
|
||||
return `${color} group-hover:${get_shifted_color(color, factor * 100)} group-active:${get_shifted_color(color, factor * 150)}`;
|
||||
}
|
||||
|
||||
function onclick(e: Event) {
|
||||
if (not_interactable) return;
|
||||
select(selected_file_ids, get_file_primary_key(file), 'toggle');
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
async function open() {
|
||||
if (is_folder) {
|
||||
await change_file_path($current_file_path + file.name + '/');
|
||||
} else {
|
||||
const path_to_file = $current_file_path + file.name;
|
||||
await run_on_all_selected_displays(open_file, true, path_to_file);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div data-testid="inode" class="flex flex-row h-{$current_height.file} w-full">
|
||||
{#if !not_interactable}
|
||||
<div class="h-{$current_height.file} aspect-square max-w-15 flex">
|
||||
<Button
|
||||
disabled={!is_folder && get_file_type(file) === null}
|
||||
title={!is_folder && get_file_type(file) === null ? 'Dateityp nicht unterstützt' : ''}
|
||||
className="flex rounded-l-lg rounded-r-none {is_folder
|
||||
? 'text-stone-450'
|
||||
: 'text-stone-800'} w-full"
|
||||
div_class="w-full"
|
||||
bg={get_selectable_color_classes(
|
||||
!is_folder && get_file_type(file) !== null,
|
||||
{
|
||||
bg: true
|
||||
},
|
||||
-50
|
||||
)}
|
||||
hover_bg={get_selectable_color_classes(
|
||||
!is_folder,
|
||||
{
|
||||
bg: true
|
||||
},
|
||||
50
|
||||
)}
|
||||
active_bg={get_selectable_color_classes(
|
||||
!is_folder,
|
||||
{
|
||||
bg: true
|
||||
},
|
||||
100
|
||||
)}
|
||||
click_function={(e) => {
|
||||
open();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{#if is_folder}
|
||||
<ArrowRight class="size-full" strokeWidth="3" />
|
||||
{:else if $missing_colliding_displays_ids && $missing_colliding_displays_ids.missing.length !== 0}
|
||||
<RefreshPlay className="size-full" />
|
||||
{:else if get_file_type(file) !== null}
|
||||
<Play class="size-full" strokeWidth="3" />
|
||||
{:else}
|
||||
<Ban class="size-full" strokeWidth="3" />
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
role="button"
|
||||
tabindex="0"
|
||||
onkeydown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') onclick(e);
|
||||
}}
|
||||
{onclick}
|
||||
class="{get_selectable_color_classes(
|
||||
!not_interactable && is_selected(get_file_primary_key(file), $selected_file_ids),
|
||||
{
|
||||
bg: true,
|
||||
hover: !not_interactable,
|
||||
active: !not_interactable,
|
||||
text: true
|
||||
}
|
||||
)} {not_interactable
|
||||
? 'rounded-lg'
|
||||
: 'rounded-r-lg cursor-pointer'} transition-colors duration-200 gap-4 flex flex-row justify-between group w-full min-w-0"
|
||||
>
|
||||
<div class="flex flex-row gap-2 min-w-0 w-full">
|
||||
<div class="aspect-square rounded-md flex justify-center items-center">
|
||||
{#if is_folder}
|
||||
<Folder class="size-full p-2" />
|
||||
{:else if $thumbnail_url || null}
|
||||
<img
|
||||
src={$thumbnail_url || null}
|
||||
alt="file_thumbnail"
|
||||
class="object-contain size-full select-none block p-1 rounded-lg"
|
||||
draggable="false"
|
||||
/>
|
||||
{:else if supported_file_type_icon[get_file_type(file)?.display_name || '']}
|
||||
{@const Icon = supported_file_type_icon[get_file_type(file)?.display_name || '']}
|
||||
<Icon class="size-full p-2" />
|
||||
{:else}
|
||||
<FileIcon class="size-full p-2" />
|
||||
{/if}
|
||||
</div>
|
||||
<div class="content-center truncate select-none w-full" title={file.name}>
|
||||
{file.name.includes('.') && !is_folder && get_file_type(file)
|
||||
? file.name.slice(0, file.name.lastIndexOf('.'))
|
||||
: file.name}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class=" p-1 flex flex-row items-center gap-1 pr-1 {get_grayed_out_text_color_strings(
|
||||
is_selected(get_file_primary_key(file), $selected_file_ids)
|
||||
)} duration-200 transition-colors"
|
||||
>
|
||||
<!-- {#if get_display_ids_where_file_is_missing($current_file_path, file, $selected_display_ids, $all_files)[1].length !== 0}
|
||||
<Button
|
||||
className="h-8 aspect-square transition-colors duration-200 !p-1.5 text-stone-100"
|
||||
bg="bg-red-500"
|
||||
click_function={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<TriangleAlert class="size-full" />
|
||||
</Button>
|
||||
{:else if get_display_ids_where_file_is_missing($current_file_path, file, $selected_display_ids, $all_files)[0].length !== 0}
|
||||
<Button
|
||||
className="h-8 aspect-square transition-colors duration-200 !p-1.5"
|
||||
bg="bg-transparent"
|
||||
hover_bg={get_selectable_color_classes(false, {
|
||||
bg: true
|
||||
})}
|
||||
active_bg={get_selectable_color_classes(false, {
|
||||
bg: true
|
||||
})}
|
||||
click_function={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<RefreshCcwDot class="size-full" />
|
||||
</Button>
|
||||
{/if} -->
|
||||
<div
|
||||
class="w-14 content-center text-center select-none text-xs whitespace-nowrap"
|
||||
title={get_created_string(file.date_created, true)}
|
||||
>
|
||||
{get_created_string(file.date_created)}
|
||||
</div>
|
||||
<div
|
||||
class="h-[70%] border {get_grayed_out_border_color_strings(
|
||||
is_selected(get_file_primary_key(file), $selected_file_ids)
|
||||
)} duration-200 transition-colors my-1"
|
||||
></div>
|
||||
<div
|
||||
class="w-12 content-center text-center select-none text-xs whitespace-nowrap truncate"
|
||||
title={file.type}
|
||||
>
|
||||
{is_folder ? 'Ordner' : (get_file_type(file)?.display_name ?? '?')}
|
||||
</div>
|
||||
<div
|
||||
class="h-[70%] border {get_grayed_out_border_color_strings(
|
||||
is_selected(get_file_primary_key(file), $selected_file_ids)
|
||||
)} duration-200 transition-colors"
|
||||
></div>
|
||||
<div
|
||||
class="w-12 content-center text-center select-none text-xs whitespace-nowrap"
|
||||
title={get_file_size_display_string(file.size, 3)}
|
||||
>
|
||||
{get_file_size_display_string(file.size)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,31 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { type DisplayStatus } from '$lib/ts/types';
|
||||
import { display_status_to_info } from '$lib/ts/utils';
|
||||
|
||||
let {
|
||||
selected,
|
||||
status,
|
||||
className = ''
|
||||
}: {
|
||||
selected: boolean;
|
||||
status: DisplayStatus;
|
||||
className?: string;
|
||||
} = $props();
|
||||
|
||||
function get_text_color(selected: boolean, status: DisplayStatus) {
|
||||
switch (status) {
|
||||
case 'app_online':
|
||||
return selected ? 'text-green-700' : 'text-green-400';
|
||||
case 'app_offline':
|
||||
return selected ? 'text-amber-700' : 'text-amber-400';
|
||||
case 'host_offline':
|
||||
return selected ? 'text-red-700' : 'text-red-400';
|
||||
default:
|
||||
return selected ? 'text-stone-700' : 'text-stone-400';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="{get_text_color(selected, status)} {className} transition-colors duration-100">
|
||||
{display_status_to_info(status)}
|
||||
</div>
|
||||
@@ -1,25 +0,0 @@
|
||||
<script lang="ts">
|
||||
let { className = '' }: { className?: string } = $props();
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.7"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="{className} lucide lucide-refresh-ccw-dot-icon lucide-refresh-ccw-dot"
|
||||
>
|
||||
<path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
|
||||
<path d="M3 3v5h5" />
|
||||
<path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" />
|
||||
<path d="M16 16h5v5" />
|
||||
<path
|
||||
d="M15.033 9.44a.647.647 0 0 1 0 1.12l-4.065 2.352a.645.645 0 0 1-.968-.56V7.648a.645.645 0 0 1 .967-.56z"
|
||||
transform="translate(0,2.0)"
|
||||
/>
|
||||
</svg>
|
||||
Reference in New Issue
Block a user