mirror of
https://github.com/wukko/cobalt.git
synced 2025-02-02 08:26:22 +01:00
web: basic ui for the download queue manager
This commit is contained in:
parent
5d75ee493d
commit
6d0ec5dd85
4 changed files with 246 additions and 4 deletions
109
web/src/components/downloads/DownloadManager.svelte
Normal file
109
web/src/components/downloads/DownloadManager.svelte
Normal file
|
@ -0,0 +1,109 @@
|
|||
<script lang="ts">
|
||||
import { onNavigate } from "$app/navigation";
|
||||
import type { SvelteComponent } from "svelte";
|
||||
|
||||
import Meowbalt from "$components/misc/Meowbalt.svelte";
|
||||
import DownloadStatus from "$components/downloads/DownloadStatus.svelte";
|
||||
import PopoverContainer from "$components/misc/PopoverContainer.svelte";
|
||||
|
||||
let popover: SvelteComponent;
|
||||
$: expanded = false;
|
||||
|
||||
$: progress = 0;
|
||||
$: indeterminate = false;
|
||||
|
||||
const popoverAction = async () => {
|
||||
expanded = !expanded;
|
||||
if (expanded) {
|
||||
popover.focus();
|
||||
}
|
||||
};
|
||||
|
||||
onNavigate(() => {
|
||||
expanded = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="downloads-manager">
|
||||
<DownloadStatus
|
||||
{indeterminate}
|
||||
{progress}
|
||||
expandAction={popover?.showPopover}
|
||||
/>
|
||||
|
||||
<PopoverContainer
|
||||
bind:this={popover}
|
||||
id="downloads-popover"
|
||||
{expanded}
|
||||
{popoverAction}
|
||||
expandStart="right"
|
||||
>
|
||||
<div id="downloads-header">
|
||||
<div class="downloads-header-title">downloads</div>
|
||||
</div>
|
||||
<div id="downloads-list">
|
||||
<div class="list-stub">
|
||||
<Meowbalt emotion="think" />
|
||||
<span>your downloads will appear here!</span>
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContainer>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#downloads-manager {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
justify-content: end;
|
||||
z-index: 9;
|
||||
pointer-events: none;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
#downloads-manager :global(#downloads-popover) {
|
||||
padding: 16px;
|
||||
max-width: 425px;
|
||||
}
|
||||
|
||||
#downloads-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.downloads-header-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#downloads-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list-stub {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--gray);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 25px;
|
||||
text-align: center;
|
||||
gap: var(--padding);
|
||||
}
|
||||
|
||||
.list-stub :global(.meowbalt) {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 535px) {
|
||||
#downloads-manager {
|
||||
top: calc(env(safe-area-inset-top) - var(--padding) + 4px);
|
||||
}
|
||||
}
|
||||
</style>
|
132
web/src/components/downloads/DownloadStatus.svelte
Normal file
132
web/src/components/downloads/DownloadStatus.svelte
Normal file
|
@ -0,0 +1,132 @@
|
|||
<script lang="ts">
|
||||
import IconArrowDown from "@tabler/icons-svelte/IconArrowDown.svelte";
|
||||
|
||||
export let indeterminate = false;
|
||||
export let progress: number = 0;
|
||||
export let expandAction: () => void;
|
||||
|
||||
$: progressStroke = `${progress}, 100`;
|
||||
const indeterminateStroke = "15, 5";
|
||||
</script>
|
||||
|
||||
<button
|
||||
id="downloads-status"
|
||||
on:click={expandAction}
|
||||
class:completed={progress >= 100}
|
||||
>
|
||||
<svg
|
||||
id="progress-ring"
|
||||
class:indeterminate
|
||||
class:progressive={progress > 0 && !indeterminate}
|
||||
>
|
||||
<circle
|
||||
cx="19"
|
||||
cy="19"
|
||||
r="16"
|
||||
fill="none"
|
||||
stroke-dasharray={indeterminate
|
||||
? indeterminateStroke
|
||||
: progressStroke}
|
||||
/>
|
||||
</svg>
|
||||
<div class="icon-holder">
|
||||
<IconArrowDown />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<style>
|
||||
#downloads-status {
|
||||
--download-status-glow: 0 0 8px 0px var(--button-elevated-hover);
|
||||
|
||||
pointer-events: all;
|
||||
padding: 7px;
|
||||
border-radius: 30px;
|
||||
box-shadow:
|
||||
var(--button-box-shadow),
|
||||
var(--download-status-glow);
|
||||
|
||||
transition: box-shadow 0.2s, background-color 0.2s;
|
||||
}
|
||||
|
||||
#downloads-status.completed {
|
||||
box-shadow:
|
||||
0 0 0 2px var(--blue) inset,
|
||||
var(--download-status-glow);
|
||||
}
|
||||
|
||||
:global([data-theme="light"]) #downloads-status.completed {
|
||||
background-color: #e0eeff;
|
||||
}
|
||||
|
||||
:global([data-theme="dark"]) #downloads-status.completed {
|
||||
background-color: #1f3249;
|
||||
}
|
||||
|
||||
.icon-holder {
|
||||
display: flex;
|
||||
background-color: var(--button-elevated-hover);
|
||||
padding: 2px;
|
||||
border-radius: 20px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.icon-holder :global(svg) {
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
stroke: var(--secondary);
|
||||
transition: stroke 0.2s;
|
||||
}
|
||||
|
||||
.completed .icon-holder {
|
||||
background-color: var(--blue);
|
||||
}
|
||||
|
||||
.completed .icon-holder :global(svg) {
|
||||
stroke: white;
|
||||
}
|
||||
|
||||
#progress-ring {
|
||||
position: absolute;
|
||||
transform: rotate(-90deg);
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
#progress-ring circle {
|
||||
stroke: var(--blue);
|
||||
stroke-width: 4;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
#progress-ring.progressive circle {
|
||||
transition: stroke-dasharray 0.2s;
|
||||
}
|
||||
|
||||
#progress-ring.progressive,
|
||||
#progress-ring.indeterminate {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#progress-ring.indeterminate {
|
||||
animation: spin 3s linear infinite;
|
||||
}
|
||||
|
||||
#progress-ring.indeterminate circle {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.completed #progress-ring {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { t } from "$lib/i18n/translations";
|
||||
|
||||
import type { MeowbaltEmotions } from "$lib/types/meowbalt";
|
||||
|
||||
export let emotion: MeowbaltEmotions;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
import NotchSticker from "$components/misc/NotchSticker.svelte";
|
||||
import DialogHolder from "$components/dialog/DialogHolder.svelte";
|
||||
import UpdateNotification from "$components/misc/UpdateNotification.svelte";
|
||||
import DownloadManager from "$components/downloads/DownloadManager.svelte";
|
||||
|
||||
$: reduceMotion =
|
||||
$settings.appearance.reduceMotion || device.prefers.reducedMotion;
|
||||
|
@ -81,14 +82,15 @@
|
|||
data-reduce-motion={reduceMotion}
|
||||
data-reduce-transparency={reduceTransparency}
|
||||
>
|
||||
{#if $updated}
|
||||
<UpdateNotification />
|
||||
{/if}
|
||||
{#if device.is.iPhone && app.is.installed}
|
||||
<NotchSticker />
|
||||
{/if}
|
||||
<DownloadManager />
|
||||
<DialogHolder />
|
||||
<Sidebar />
|
||||
{#if $updated}
|
||||
<UpdateNotification />
|
||||
{/if}
|
||||
<div id="content">
|
||||
{#if ($turnstileEnabled && $page.url.pathname === "/") || $turnstileCreated}
|
||||
<Turnstile />
|
||||
|
|
Loading…
Reference in a new issue