fix: card, tooltip, and scrollbar fixes

This commit is contained in:
Maya 2025-07-26 23:58:30 +03:00
parent 8c182457fe
commit bc055e6b98
No known key found for this signature in database
4 changed files with 197 additions and 73 deletions

View File

@ -4,15 +4,47 @@
interface Props { interface Props {
children: () => any; children: () => any;
text: string; text: string;
className?: string;
position?: "top" | "bottom" | "left" | "right"; position?: "top" | "bottom" | "left" | "right";
} }
let { children, text, position = "top" }: Props = $props(); let { children, text, className, position = "top" }: Props = $props();
let showTooltip = $state(false); let showTooltip = $state(false);
let timeout: number = 0; let timeout: number = 0;
let triggerElement: HTMLElement;
let tooltipPosition = $state({ x: 0, y: 0 });
function show() { function show() {
timeout = setTimeout(() => { timeout = setTimeout(() => {
if (!triggerElement) return;
const rect = triggerElement.getBoundingClientRect();
switch (position) {
case "top":
tooltipPosition = {
x: rect.left + rect.width / 2,
y: rect.top - 10,
};
break;
case "bottom":
tooltipPosition = {
x: rect.left + rect.width / 2,
y: rect.bottom + 10,
};
break;
case "left":
tooltipPosition = {
x: rect.left - 10,
y: rect.top + rect.height / 2,
};
break;
case "right":
tooltipPosition = {
x: rect.right + 10,
y: rect.top + rect.height / 2,
};
break;
}
showTooltip = true; showTooltip = true;
}, 500); }, 500);
} }
@ -24,7 +56,8 @@
</script> </script>
<div <div
class="relative inline-block" bind:this={triggerElement}
class="relative inline-block {className}"
onmouseenter={show} onmouseenter={show}
onmouseleave={hide} onmouseleave={hide}
onfocusin={show} onfocusin={show}
@ -34,26 +67,28 @@
role="tooltip" role="tooltip"
> >
{@render children()} {@render children()}
{#if showTooltip}
<div
class="tooltip tooltip-{position}"
transition:fade={{
duration: 100,
}}
>
{text}
</div>
{/if}
</div> </div>
{#if showTooltip}
<div
class="tooltip tooltip-{position}"
style="left: {tooltipPosition.x}px; top: {tooltipPosition.y}px;"
transition:fade={{
duration: 100,
}}
>
{text}
</div>
{/if}
<style> <style>
.tooltip { .tooltip {
--border-size: 1px; --border-size: 1px;
@apply absolute z-10 bg-panel-alt text-foreground border border-stone-400 dynadark:border-white drop-shadow-lg text-xs px-4 py-2 rounded-full whitespace-nowrap pointer-events-none; @apply fixed bg-panel-alt text-foreground border border-stone-400 dynadark:border-white drop-shadow-lg text-xs px-4 py-2 rounded-full whitespace-nowrap pointer-events-none z-[999];
} }
.tooltip-top { .tooltip-top {
@apply bottom-full left-1/2 -translate-x-1/2 mb-3; transform: translate(-50%, -100%);
} }
.tooltip-top::after { .tooltip-top::after {
@ -67,7 +102,7 @@
} }
.tooltip-bottom { .tooltip-bottom {
@apply top-full left-1/2 -translate-x-1/2 mt-3; transform: translate(-50%, 20%);
} }
.tooltip-bottom::after { .tooltip-bottom::after {
@ -81,7 +116,7 @@
} }
.tooltip-left { .tooltip-left {
@apply right-full top-1/2 -translate-y-1/2 mr-3; transform: translate(-100%, -50%);
} }
.tooltip-left::after { .tooltip-left::after {
@ -89,7 +124,7 @@
} }
.tooltip-right { .tooltip-right {
@apply left-full top-1/2 -translate-y-1/2 ml-3; transform: translate(0%, -50%);
} }
.tooltip-right::after { .tooltip-right::after {

View File

@ -277,8 +277,6 @@ const toArgs = (ext: string): string[] => {
"18", "18",
"-tune", "-tune",
"stillimage", "stillimage",
"-c:a",
"aac",
); );
break; break;
} }

View File

@ -335,6 +335,44 @@ body {
@apply bg-accent-purple !text-black; @apply bg-accent-purple !text-black;
} }
// firefox
* {
scrollbar-width: thin;
scrollbar-color: var(--bg-separator) transparent;
}
// other browsers
*::-webkit-scrollbar {
width: 6px;
height: 6px;
}
*::-webkit-scrollbar-track {
background: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: var(--bg-separator);
border-radius: 3px;
border: none;
opacity: 0.7;
}
*::-webkit-scrollbar-thumb:hover {
background-color: var(--bg-separator);
opacity: 1;
}
*::-webkit-scrollbar-corner {
background: transparent;
}
*::-webkit-scrollbar-button {
display: none;
width: 0;
height: 0;
}
@layer components { @layer components {
select { select {
@apply appearance-none; @apply appearance-none;

View File

@ -7,6 +7,7 @@
import { AudioLines, BookText, Check, Film, Image } from "lucide-svelte"; import { AudioLines, BookText, Check, Film, Image } from "lucide-svelte";
import { m } from "$lib/paraglide/messages"; import { m } from "$lib/paraglide/messages";
import { link } from "$lib/store/index.svelte"; import { link } from "$lib/store/index.svelte";
import { onMount } from "svelte";
const getSupportedFormats = (name: string) => const getSupportedFormats = (name: string) =>
converters converters
@ -72,6 +73,30 @@
} }
return ""; return "";
}; };
let scrollContainers: HTMLElement[] = [];
// svelte-ignore state_referenced_locally
let showBlur = $state(Array(Object.keys(status).length).fill(false));
const checkScrollable = (index: number) => {
const container = scrollContainers[index];
if (!container) return;
showBlur[index] = container.scrollHeight > container.clientHeight;
};
onMount(() => {
const handleResize = () => {
for (let i = 0; i < scrollContainers.length; i++)
checkScrollable(i);
};
handleResize();
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
});
</script> </script>
<div class="max-w-6xl w-full mx-auto px-6 md:px-8"> <div class="max-w-6xl w-full mx-auto px-6 md:px-8">
@ -103,7 +128,7 @@
<h2 class="text-center text-4xl">{m["upload.cards.title"]()}</h2> <h2 class="text-center text-4xl">{m["upload.cards.title"]()}</h2>
<div class="flex gap-4 mt-8 md:flex-row flex-col"> <div class="flex gap-4 mt-8 md:flex-row flex-col">
{#each Object.entries(status) as [key, s]} {#each Object.entries(status) as [key, s], i}
{@const Icon = s.icon} {@const Icon = s.icon}
<div class="file-category-card w-full flex flex-col gap-4"> <div class="file-category-card w-full flex flex-col gap-4">
<div class="file-category-card-inner"> <div class="file-category-card-inner">
@ -120,61 +145,89 @@
<span>{s.title}</span> <span>{s.title}</span>
</div> </div>
<div class="file-category-card-content flex-grow gap-4"> <div class="file-category-card-content flex-grow relative">
{#if key === "Video"} <div
<p> class="h-[12.25rem] overflow-y-auto overflow-x-hidden"
{@html link( bind:this={scrollContainers[i]}
"wiki_link", >
m["upload.cards.video_server_processing"](), <div class="flex flex-col gap-4">
"https://github.com/VERT-sh/VERT/wiki/How-to-convert-video-with-VERT", {#if key === "Video"}
)} <p>
</p> {@html link(
{:else} "wiki_link",
<p class="flex tems-center justify-center gap-2"> m[
<Check size="20" /> "upload.cards.video_server_processing"
{m["upload.cards.local_supported"]()} ](),
</p> "https://github.com/VERT-sh/VERT/wiki/How-to-convert-video-with-VERT",
{/if} )}
<p> </p>
{@html m["upload.cards.status.text"]({ {:else}
status: s.ready <p
? m["upload.cards.status.ready"]() class="flex tems-center justify-center gap-2"
: m["upload.cards.status.not_ready"](),
})}
</p>
<div>
<span class="flex flex-wrap justify-center">
<b
>{m[
"upload.cards.supported_formats"
]()}&nbsp;</b
>
{#each s.formats.split(", ") as format, index}
{@const isPartial = format.endsWith("*")}
{@const formatName = isPartial
? format.slice(0, -1)
: format}
<span
class="text-sm font-normal flex items-center"
> >
{#if isPartial} <Check size="20" />
<Tooltip {m["upload.cards.local_supported"]()}
text={getTooltip(formatName)} </p>
{/if}
<p>
{@html m["upload.cards.status.text"]({
status: s.ready
? m["upload.cards.status.ready"]()
: m[
"upload.cards.status.not_ready"
](),
})}
</p>
<div class="flex flex-col items-center">
<b
>{m[
"upload.cards.supported_formats"
]()}&nbsp;</b
>
<p
class="flex flex-wrap justify-center leading-tight px-2"
>
{#each s.formats.split(", ") as format, index}
{@const isPartial =
format.endsWith("*")}
{@const formatName = isPartial
? format.slice(0, -1)
: format}
<span
class="text-sm font-normal flex items-center"
> >
{formatName}<span {#if isPartial}
class="text-red-500">*</span <Tooltip
> text={getTooltip(
</Tooltip> formatName,
{:else} )}
{formatName} >
{/if} {formatName}<span
{#if index < s.formats.split(", ").length - 1} class="text-red-500"
<span>,&nbsp;</span> >*</span
{/if} >
</span> </Tooltip>
{/each} {:else}
</span> {formatName}
{/if}
{#if index < s.formats.split(", ").length - 1}
<span>,&nbsp;</span>
{/if}
</span>
{/each}
</p>
</div>
</div>
</div> </div>
<!-- blur at bottom if scrollable -->
{#if showBlur[i]}
<div
class="absolute left-0 bottom-0 w-full h-10 pointer-events-none"
style="
background: linear-gradient(to top, rgba(255,255,255,0.8), transparent 100%);
"
></div>
{/if}
</div> </div>
</div> </div>
{/each} {/each}
@ -184,7 +237,7 @@
<style> <style>
.file-category-card { .file-category-card {
@apply bg-panel rounded-2xl p-5 shadow-panel; @apply bg-panel rounded-2xl p-5 shadow-panel relative;
} }
.file-category-card p { .file-category-card p {