mirror of https://github.com/VERT-sh/VERT.git
feat: use overlayscrollbars for cards
finally no more shifting on chromium
This commit is contained in:
parent
ee0de6e178
commit
2f5fddcc6e
6
bun.lock
6
bun.lock
|
@ -17,6 +17,8 @@
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-svelte": "^0.475.0",
|
"lucide-svelte": "^0.475.0",
|
||||||
"music-metadata": "^11.0.0",
|
"music-metadata": "^11.0.0",
|
||||||
|
"overlayscrollbars": "^2.11.5",
|
||||||
|
"overlayscrollbars-svelte": "^0.5.5",
|
||||||
"p-queue": "^8.1.0",
|
"p-queue": "^8.1.0",
|
||||||
"riff-file": "^1.0.3",
|
"riff-file": "^1.0.3",
|
||||||
"svelte-stripe": "^1.4.0",
|
"svelte-stripe": "^1.4.0",
|
||||||
|
@ -641,6 +643,10 @@
|
||||||
|
|
||||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||||
|
|
||||||
|
"overlayscrollbars": ["overlayscrollbars@2.11.5", "", {}, "sha512-vTUfCtjJbTjiarrxl9qdK04ZxlQdB4ugXfiqctVZytYDXH259OM4whROMGDE6T8uCYmSYPqiOFIKZ1erVkJnFg=="],
|
||||||
|
|
||||||
|
"overlayscrollbars-svelte": ["overlayscrollbars-svelte@0.5.5", "", { "peerDependencies": { "overlayscrollbars": "^2.0.0", "svelte": "^5.0.0" } }, "sha512-+dRW3YZSvFbKi5vDCpnUOHuoPLLSdu0BUVVMYZdmfVghu7XkafDRebG2y91/ImPqj6YDAUsz1rcWVYhCJSS/pQ=="],
|
||||||
|
|
||||||
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
||||||
|
|
||||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
||||||
|
|
|
@ -50,6 +50,8 @@
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-svelte": "^0.475.0",
|
"lucide-svelte": "^0.475.0",
|
||||||
"music-metadata": "^11.0.0",
|
"music-metadata": "^11.0.0",
|
||||||
|
"overlayscrollbars": "^2.11.5",
|
||||||
|
"overlayscrollbars-svelte": "^0.5.5",
|
||||||
"p-queue": "^8.1.0",
|
"p-queue": "^8.1.0",
|
||||||
"riff-file": "^1.0.3",
|
"riff-file": "^1.0.3",
|
||||||
"svelte-stripe": "^1.4.0",
|
"svelte-stripe": "^1.4.0",
|
||||||
|
|
|
@ -335,44 +335,6 @@ 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;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
dropping,
|
dropping,
|
||||||
vertdLoaded,
|
vertdLoaded,
|
||||||
locale,
|
locale,
|
||||||
updateLocale,
|
|
||||||
} from "$lib/store/index.svelte";
|
} from "$lib/store/index.svelte";
|
||||||
import "$lib/css/app.scss";
|
import "$lib/css/app.scss";
|
||||||
import { browser } from "$app/environment";
|
import { browser } from "$app/environment";
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
import Uploader from "$lib/components/functional/Uploader.svelte";
|
import Uploader from "$lib/components/functional/Uploader.svelte";
|
||||||
import Tooltip from "$lib/components/visual/Tooltip.svelte";
|
import Tooltip from "$lib/components/visual/Tooltip.svelte";
|
||||||
import { converters } from "$lib/converters";
|
import { converters } from "$lib/converters";
|
||||||
import { theme, vertdLoaded } from "$lib/store/index.svelte";
|
import { vertdLoaded } from "$lib/store/index.svelte";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
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 { OverlayScrollbarsComponent } from "overlayscrollbars-svelte";
|
||||||
|
import { browser } from "$app/environment";
|
||||||
|
import "overlayscrollbars/overlayscrollbars.css";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
||||||
const getSupportedFormats = (name: string) =>
|
const getSupportedFormats = (name: string) =>
|
||||||
|
@ -79,33 +81,12 @@
|
||||||
let showBlur = $state(Array(Object.keys(status).length).fill(false));
|
let showBlur = $state(Array(Object.keys(status).length).fill(false));
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const isFirefox = /firefox/i.test(navigator.userAgent);
|
|
||||||
|
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
for (let i = 0; i < scrollContainers.length; i++) {
|
for (let i = 0; i < scrollContainers.length; i++) {
|
||||||
// show bottom blur if scrollable
|
// show bottom blur if scrollable
|
||||||
const container = scrollContainers[i];
|
const container = scrollContainers[i];
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
showBlur[i] = container.scrollHeight > container.clientHeight;
|
showBlur[i] = container.scrollHeight > container.clientHeight;
|
||||||
|
|
||||||
// if not on firefox, add ml-2 to card content if scrollable
|
|
||||||
// doing this because i can't figure out how to make the scrollbar *not* take up DOM space (shifting the contents to the left)
|
|
||||||
if (!isFirefox && scrollContainers[i]) {
|
|
||||||
const card = scrollContainers[i].closest(
|
|
||||||
".file-category-card",
|
|
||||||
);
|
|
||||||
const cardContent = card?.querySelector(
|
|
||||||
".file-category-card-content",
|
|
||||||
);
|
|
||||||
if (cardContent) {
|
|
||||||
const hasML2 = cardContent.classList.contains("ml-2");
|
|
||||||
if (showBlur[i] && !hasML2) {
|
|
||||||
cardContent.classList.add("ml-2");
|
|
||||||
} else if (!showBlur[i] && hasML2) {
|
|
||||||
cardContent.classList.remove("ml-2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -147,124 +128,140 @@
|
||||||
<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], i}
|
{#if browser}
|
||||||
{@const Icon = s.icon}
|
{#each Object.entries(status) as [key, s], i}
|
||||||
<div class="file-category-card w-full flex flex-col gap-4">
|
{@const Icon = s.icon}
|
||||||
<div class="file-category-card-inner">
|
<div class="file-category-card w-full flex flex-col gap-4">
|
||||||
<div
|
<div class="file-category-card-inner">
|
||||||
class={clsx("icon-container", {
|
|
||||||
"bg-accent-blue": key === "Images",
|
|
||||||
"bg-accent-purple": key === "Audio",
|
|
||||||
"bg-accent-green": key === "Documents",
|
|
||||||
"bg-accent-red": key === "Video",
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Icon size="20" />
|
|
||||||
</div>
|
|
||||||
<span>{s.title}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="file-category-card-content flex-grow relative">
|
|
||||||
<div
|
|
||||||
class="h-[12.25rem] overflow-y-auto overflow-x-hidden"
|
|
||||||
bind:this={scrollContainers[i]}
|
|
||||||
>
|
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
{#if key === "Video"}
|
|
||||||
<p
|
|
||||||
class="flex tems-center justify-center gap-2"
|
|
||||||
>
|
|
||||||
<Check size="20" />
|
|
||||||
<Tooltip
|
|
||||||
text={m[
|
|
||||||
"upload.tooltip.video_server_processing"
|
|
||||||
]()}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<a
|
|
||||||
href="https://github.com/VERT-sh/VERT/blob/main/docs/VIDEO_CONVERSION.md"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
{m[
|
|
||||||
"upload.cards.video_server_processing"
|
|
||||||
]()}
|
|
||||||
</a>
|
|
||||||
<span
|
|
||||||
class="text-red-500 -ml-0.5"
|
|
||||||
>*</span
|
|
||||||
>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</p>
|
|
||||||
{:else}
|
|
||||||
<p
|
|
||||||
class="flex tems-center justify-center gap-2"
|
|
||||||
>
|
|
||||||
<Check size="20" />
|
|
||||||
{m["upload.cards.local_supported"]()}
|
|
||||||
</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"
|
|
||||||
]()} </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"
|
|
||||||
>
|
|
||||||
{#if isPartial}
|
|
||||||
<Tooltip
|
|
||||||
text={getTooltip(
|
|
||||||
formatName,
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{formatName}<span
|
|
||||||
class="text-red-500"
|
|
||||||
>*</span
|
|
||||||
>
|
|
||||||
</Tooltip>
|
|
||||||
{:else}
|
|
||||||
{formatName}
|
|
||||||
{/if}
|
|
||||||
{#if index < s.formats.split(", ").length - 1}
|
|
||||||
<span>, </span>
|
|
||||||
{/if}
|
|
||||||
</span>
|
|
||||||
{/each}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- blur at bottom if scrollable -->
|
|
||||||
{#if showBlur[i]}
|
|
||||||
<div
|
<div
|
||||||
class="absolute left-0 bottom-0 w-full h-10 pointer-events-none"
|
class={clsx("icon-container", {
|
||||||
style={`background: linear-gradient(to top, var(--bg-panel), transparent 100%);`}
|
"bg-accent-blue": key === "Images",
|
||||||
></div>
|
"bg-accent-purple": key === "Audio",
|
||||||
{/if}
|
"bg-accent-green": key === "Documents",
|
||||||
|
"bg-accent-red": key === "Video",
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Icon size="20" />
|
||||||
|
</div>
|
||||||
|
<span>{s.title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="file-category-card-content flex-grow relative"
|
||||||
|
>
|
||||||
|
<OverlayScrollbarsComponent
|
||||||
|
options={{
|
||||||
|
scrollbars: {
|
||||||
|
autoHide: "move",
|
||||||
|
autoHideDelay: 1500,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
defer
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-4 h-[12.25rem]"
|
||||||
|
bind:this={scrollContainers[i]}
|
||||||
|
>
|
||||||
|
{#if key === "Video"}
|
||||||
|
<p
|
||||||
|
class="flex tems-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<Check size="20" />
|
||||||
|
<Tooltip
|
||||||
|
text={m[
|
||||||
|
"upload.tooltip.video_server_processing"
|
||||||
|
]()}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<a
|
||||||
|
href="https://github.com/VERT-sh/VERT/blob/main/docs/VIDEO_CONVERSION.md"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{m[
|
||||||
|
"upload.cards.video_server_processing"
|
||||||
|
]()}
|
||||||
|
</a>
|
||||||
|
<span
|
||||||
|
class="text-red-500 -ml-0.5"
|
||||||
|
>*</span
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</p>
|
||||||
|
{:else}
|
||||||
|
<p
|
||||||
|
class="flex tems-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<Check size="20" />
|
||||||
|
{m[
|
||||||
|
"upload.cards.local_supported"
|
||||||
|
]()}
|
||||||
|
</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"
|
||||||
|
]()} </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"
|
||||||
|
>
|
||||||
|
{#if isPartial}
|
||||||
|
<Tooltip
|
||||||
|
text={getTooltip(
|
||||||
|
formatName,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{formatName}<span
|
||||||
|
class="text-red-500"
|
||||||
|
>*</span
|
||||||
|
>
|
||||||
|
</Tooltip>
|
||||||
|
{:else}
|
||||||
|
{formatName}
|
||||||
|
{/if}
|
||||||
|
{#if index < s.formats.split(", ").length - 1}
|
||||||
|
<span>, </span>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
{/each}
|
||||||
|
</p>
|
||||||
|
</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, var(--bg-panel), transparent 100%);`}
|
||||||
|
></div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{/each}
|
||||||
{/each}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue