change install buttons and other small fixes (#464)

* change install buttons and other small fixes

* wtf is wrong with prettier

* wtf is wrong with prettier

* fix button vertical alignment on search results page
This commit is contained in:
ABevier 2023-04-15 00:18:18 -04:00 committed by GitHub
parent 0163d30b28
commit 7af1e543f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 236 additions and 207 deletions

View file

@ -13,6 +13,6 @@ declare namespace svelte.JSX {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface HTMLAttributes<T> {
onclick_outside?: () => void;
leave_delay?: () => void;
onleave_delay?: () => void;
}
}

View file

@ -8,9 +8,9 @@
import type { GUIPackage } from "$libs/types";
import { packagesStore } from "$libs/stores";
import { shellOpenExternal } from "@native";
import InstallButton from "$components/install-button/install-button.svelte";
import { findAvailableVersions } from "$libs/packages/pkg-utils";
import { trimGithubSlug } from "$libs/github";
import PackageVersionSelector from "$components/package-install-button/package-version-selector.svelte";
export let pkg: GUIPackage;
let installing = false;
@ -51,7 +51,7 @@
{/if}
<p class="mt-4 text-sm">{pkg.desc}</p>
<menu class="mt-4 grid h-10 grid-cols-3 gap-4 text-xs">
<InstallButton
<PackageVersionSelector
buttonSize="large"
{pkg}
availableVersions={findAvailableVersions(pkg)}

View file

@ -1,12 +1,11 @@
<script lang="ts">
import "../../app.css";
import ProgressCircle from "@tea/ui/progress-circle/progress-circle.svelte";
import InstallButton from "../install-button/install-button.svelte";
import type { GUIPackage } from "$libs/types";
import { findRecentInstalledVersion } from "$libs/packages/pkg-utils";
import PackageInstallButton from "$components/package-install-button/package-install-button.svelte";
export let pkg: GUIPackage;
export let availableVersions: string[];
export let link: string;
export let progessLoading = 0;
@ -14,11 +13,7 @@
? "https://tea.xyz/Images/package-thumb-nolabel4.jpg"
: pkg.thumb_image_url;
export let onClickCTA = async (_version: string) => {
console.log("do nothing");
};
export let onUninstall = async () => {
export let onClickCTA = async () => {
console.log("do nothing");
};
@ -53,7 +48,14 @@
</article>
<div class="relative mt-3.5 flex w-full">
<div class="install-button" on:mousedown={preventPropagation}>
<InstallButton {pkg} {availableVersions} onClick={onClickCTA} uninstall={onUninstall} />
<PackageInstallButton
{pkg}
onClick={(evt) => {
// prevent default to prevent the link that this button is inside of from being followed
evt?.preventDefault();
onClickCTA();
}}
/>
</div>
</div>
<div class="relative mt-1.5 h-[10px] leading-[10px]">

View file

@ -33,6 +33,8 @@
[PackageStates.UNINSTALLED]: ""
};
const hasVersionSelectorDropdown = !!$$slots.selector;
$: ctaLabel = $t(`package.cta-${pkg.state}`);
</script>
@ -45,28 +47,24 @@
>
<div class="version-button h-full">
<div class="flex h-full flex-col justify-center p-2">
{#if pkg.state === PackageStates.AVAILABLE}
{#if hasVersionSelectorDropdown}
<div class="flex items-center justify-between gap-x-2">
<div class="flex items-center gap-x-2">
<div>{ctaLabel}</div>
<div class="version-label install-badge">{pkg.version}</div>
<div class="version-label {badgeClass[pkg.state]}">{pkg.version}</div>
</div>
<i class="icon-downward-arrow flex" />
</div>
{:else if pkg.state === PackageStates.NEEDS_UPDATE || pkg.state === PackageStates.INSTALLED}
{:else}
<div class="flex items-center justify-center gap-x-2">
<div>{ctaLabel}</div>
<div class="version-label {badgeClass[pkg.state]}">{pkg.version}</div>
</div>
{:else}
<div class="flex items-center justify-center">
{ctaLabel}
</div>
{/if}
</div>
<!-- This slot holds the drop down menu and it inside of the button so that the
hover effect remain on the button while the user is hovering the dropdown items-->
<slot />
<slot name="selector" />
</div>
</Button>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { PackageStates, type GUIPackage } from "$libs/types";
import clickOutside from "@tea/ui/lib/clickOutside";
import PackageStateButton from "./package-state-button.svelte";
import PackageStateButton from "./package-install-button.svelte";
export let buttonSize: "small" | "large" = "small";
export let pkg: GUIPackage;
@ -48,7 +48,7 @@
<div class="dropdown z-10" use:clickOutside on:click_outside={handleClickOutside}>
<PackageStateButton {buttonSize} {pkg} onClick={toggleOpen}>
<div class="pt-2">
<div slot="selector" class="pt-2">
<div class="version-list" class:visible={isOpened}>
{#if (pkg?.installed_versions || []).length > 0}
<!-- svelte-ignore a11y-click-events-have-key-events -->
@ -112,7 +112,7 @@
}
.installable-version:hover {
border: 1px solid #949494;
outline: 1px solid #949494;
background-color: rgba(148, 148, 148, 0.35);
}

View file

@ -1,11 +1,10 @@
<script lang="ts">
import "$appcss";
import type { GUIPackage } from "$libs/types";
import { PackageStates, type GUIPackage } from "$libs/types";
import { packagesStore } from "$libs/stores";
import { onMount } from "svelte";
import PackageCard from "$components/package-card/package-card.svelte";
import { findAvailableVersions } from "$libs/packages/pkg-utils";
export let tab = "all";
export let pkg: GUIPackage;
@ -17,11 +16,16 @@
<PackageCard
{pkg}
availableVersions={findAvailableVersions(pkg)}
link="/packages/{pkg.slug}?tab={tab}"
progessLoading={pkg.install_progress_percentage}
onClickCTA={(version) => packagesStore.installPkg(pkg, version)}
onUninstall={async () => {
packagesStore.uninstallPkg(pkg);
onClickCTA={async () => {
if (
[PackageStates.INSTALLED, PackageStates.INSTALLING, PackageStates.UPDATING].includes(
pkg.state
)
) {
return;
}
packagesStore.installPkg(pkg);
}}
/>

View file

@ -1,83 +1,93 @@
<script lang="ts">
import { authStore, navStore } from '$libs/stores';
import SelectLang from '$components/select-lang/select-lang.svelte';
import { baseUrl } from '$libs/v1-client';
import { shellOpenExternal, submitLogs } from '@native';
import mouseLeaveDelay from "@tea/ui/lib/mouse-leave-delay";
import { getSession } from '@native';
import { authStore, navStore } from "$libs/stores";
import SelectLang from "$components/select-lang/select-lang.svelte";
import { baseUrl } from "$libs/v1-client";
import { shellOpenExternal, submitLogs } from "@native";
import mouseLeaveDelay from "@tea/ui/lib/mouse-leave-delay";
import { getSession } from "@native";
const { user } = authStore;
const { user } = authStore;
let authenticating = false;
let authenticating = false;
const openGithub = async () => {
authenticating = true;
if (!authenticating) {
try {
const session = await getSession();
if (session && session.device_id) {
shellOpenExternal(`${baseUrl}/auth/user?device_id=${session.device_id}`);
authStore.pollSession();
} else {
throw new Error("possible no internet connection");
}
} catch (error) {
submittedMessage = (error as Error).message;
console.error(error);
} finally {
authenticating = false;
}
}
const openGithub = async () => {
authenticating = true;
if (!authenticating) {
try {
const session = await getSession();
if (session && session.device_id) {
shellOpenExternal(`${baseUrl}/auth/user?device_id=${session.device_id}`);
authStore.pollSession();
} else {
throw new Error("possible no internet connection");
}
} catch (error) {
submittedMessage = (error as Error).message;
console.error(error);
} finally {
authenticating = false;
}
}
};
let submittedMessage = "";
const onSubmitLogs = async () => {
if (submittedMessage !== "syncing...") {
submittedMessage = "syncing..."
const msg = await submitLogs();
submittedMessage = msg;
}
}
let submittedMessage = "";
const onSubmitLogs = async () => {
if (submittedMessage !== "syncing...") {
submittedMessage = "syncing...";
const msg = await submitLogs();
submittedMessage = msg;
}
};
const hidePopup = () => {
navStore.sideNavOpen.set(false);
}
const hidePopup = () => {
navStore.sideNavOpen.set(false);
};
</script>
<nav class="w-full p-2 text-sm" use:mouseLeaveDelay={2000} on:leave_delay={() => hidePopup()}>
{#if $user}
<section class="flex items-center justify-between p-1 hover:bg-gray hover:border hover:border-white rounded-sm hover:bg-opacity-90 hover:text-black">
<div class="text-white">@{$user?.login}</div>
<img id="avatar" class="rounded-sm" src={$user?.avatar_url || '/images/bored-ape.png'} alt="profile" />
</section>
{:else}
<button
class="mt-2 p-1 transition-all rounded-sm w-full h-8 text-left hover:bg-gray hover:border focus:bg-secondary bg-opacity-40"
class:animate-pulse={authenticating}
on:click={openGithub}>
login
</button>
{/if}
<hr class="mt-2 border border-gray border-b-0 border-t-0"/>
<SelectLang/>
<hr class="border border-gray border-b-0 border-t-0"/>
<button
class="mt-2 p-1 transition-all rounded-sm w-full h-8 text-left hover:bg-gray hover:border focus:bg-secondary"
class:animate-pulse={submittedMessage === "syncing..."}
on:click={onSubmitLogs}>
submit logs
</button>
{#if submittedMessage}
<p class="text-gray text-xs mt-2">{submittedMessage}</p>
{/if}
{#if $user}
<section
class="hover:bg-gray outline-gray flex items-center justify-between p-1 outline-1 hover:bg-opacity-25 hover:text-black hover:outline"
>
<div class="text-white">@{$user?.login}</div>
<img
id="avatar"
class="rounded-sm"
src={$user?.avatar_url || "/images/bored-ape.png"}
alt="profile"
/>
</section>
{:else}
<button
class="hover:bg-gray outline-gray focus:bg-secondary h-8 w-full p-1 text-left outline-1 transition-all hover:bg-opacity-25 hover:outline"
class:animate-pulse={authenticating}
on:click={openGithub}
>
login
</button>
{/if}
<hr class="mt-1" />
<SelectLang />
<hr />
<button
class="hover:bg-gray outline-gray focus:bg-secondary h-8 w-full p-1 text-left outline-1 transition-all hover:bg-opacity-25 hover:outline"
class:animate-pulse={submittedMessage === "syncing..."}
on:click={onSubmitLogs}
>
submit logs
</button>
{#if submittedMessage}
<p class="text-gray mt-2 text-xs">{submittedMessage}</p>
{/if}
</nav>
<style>
hr {
border-width: 1px;
}
hr {
border: 1px solid #272626;
}
#avatar {
height: 24px !important;
width: 24px !important;
}
</style>
#avatar {
height: 24px !important;
width: 24px !important;
}
</style>

View file

@ -1,14 +1,14 @@
<script lang="ts">
import InstallButton from "$components/install-button/install-button.svelte";
import type { GUIPackage } from "$libs/types";
import { packagesStore } from "$libs/stores";
import { onMount } from "svelte";
import ImgLoader from "@tea/ui/img-loader/img-loader.svelte";
import { findAvailableVersions } from "$libs/packages/pkg-utils";
import { goto } from "$app/navigation";
import { goto } from "$app/navigation";
import PackageInstallButton from "$components/package-install-button/package-install-button.svelte";
export let pkg: GUIPackage;
export let onClick: (_version: string) => Promise<void>;
export let onClick: () => Promise<void>;
export let onClose: () => void;
onMount(() => {
@ -20,7 +20,7 @@
const gotoPackagePage = () => {
goto(`/packages/${pkg.slug}?tab=all`);
onClose();
}
};
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
@ -38,8 +38,9 @@
<p class="line-clamp-2 text-xs">{pkg.desc}</p>
</header>
<aside>
<InstallButton {pkg} {availableVersions} {onClick} />
<footer class="mt-2 text-center text-xs">v{pkg.version}</footer>
<div>
<PackageInstallButton {pkg} {onClick} />
</div>
</aside>
</figure>
@ -47,4 +48,12 @@
figure:hover {
background-color: #252525;
}
</style>
aside {
display: flex;
flex-direction: column;
justify-content: center;
min-width: 140px;
margin-right: 22px;
}
</style>

View file

@ -1,17 +1,17 @@
<script lang="ts">
import { searchStore } from '$libs/stores';
import type { GUIPackage } from '$libs/types';
import SearchInput from '@tea/ui/search-input/search-input.svelte';
import { t } from '$libs/translations';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
import { packagesStore, searchStore } from "$libs/stores";
import type { GUIPackage } from "$libs/types";
import SearchInput from "@tea/ui/search-input/search-input.svelte";
import { t } from "$libs/translations";
import Preloader from "@tea/ui/Preloader/Preloader.svelte";
import Package from "$components/packages/package.svelte";
import { PackageStates } from '$libs/types';
import { PackageStates } from "$libs/types";
import PackageResult from "./package-search-result.svelte";
import Mousetrap from 'mousetrap';
import Mousetrap from "mousetrap";
// import Posts from '@tea/ui/posts/posts.svelte';
import { installPackage } from '@native';
import { onMount } from 'svelte';
import { installPackage } from "@native";
import { onMount } from "svelte";
const { searching, packagesSearch } = searchStore;
// import type { AirtablePost } from '@tea/ui/types';
@ -42,30 +42,32 @@
searchStore.searching.subscribe((v) => (loading = v));
const onClose = () => {
term = '';
term = "";
searchStore.searching.set(false);
};
</script>
{#if $searching === true}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div id="bg-close" class="z-40" on:click={onClose}></div>
<div id="bg-close" class="z-40" on:click={onClose} />
<section class="z-50">
<header class="flex border border-gray border-t-0 border-x-0 bg-black">
<header class="border-gray flex border border-x-0 border-t-0 bg-black">
<div class="relative w-full">
<SearchInput
class="w-full rounded-sm h-9"
class="h-9 w-full rounded-sm"
size="small"
autofocus={true}
placeholder="{$t("store-search-placeholder")}"
placeholder={$t("store-search-placeholder")}
onSearch={(search) => {
term = search;
searchStore.search(search);
}}
/>
<div class="absolute top-2 right-3 opacity-50 flex items-center gap-1">
<button class="text-xs mt-1">clear</button>
<kbd class=" bg-gray text-white px-2 mt-1 rounded-sm flex items-center">
<span class="text-xs">ctrl + shift + del</span>
<div class="absolute top-2 right-3 flex items-center gap-1 pt-[1px] opacity-50">
<span class="mr-1 text-xs">clear</span>
<kbd class=" bg-gray flex items-center rounded-sm px-2 pt-[1px] text-white">
<span class="mr-1.5 text-lg leading-4"></span>
<span class="text-xs">+ shift + del</span>
</kbd>
</div>
</div>
@ -79,18 +81,21 @@
<ul class="flex flex-col gap-2 p-2">
{#if $packagesSearch.length > 0}
{#each $packagesSearch as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<div class={pkg.state === PackageStates.INSTALLING ? "animate-pulse" : ""}>
<PackageResult
{pkg}
{onClose}
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg, pkg.version);
pkg.state = PackageStates.INSTALLED;
} catch (error) {
console.error(error);
if (
[
PackageStates.INSTALLED,
PackageStates.INSTALLING,
PackageStates.UPDATING
].includes(pkg.state)
) {
return;
}
packagesStore.installPkg(pkg);
}}
/>
</div>
@ -119,7 +124,7 @@
{/if} -->
</div>
{:else}
<div class="w-full h-full flex flex-col justify-center bg-black">
<div class="flex h-full w-full flex-col justify-center bg-black">
<p class="text-gray text-center">start typing to search</p>
</div>
{/if}
@ -160,7 +165,6 @@
overflow-y: scroll;
}
/* width */
::-webkit-scrollbar {
width: 6px;

View file

@ -1,16 +1,16 @@
<script lang="ts">
import { t, locales, locale } from '$libs/translations';
import SelectExpand from "@tea/ui/select-expand/select-expand.svelte";
import { t, locales, locale } from "$libs/translations";
import SelectExpand from "@tea/ui/select-expand/select-expand.svelte";
const label = "Language";
const label = "language";
</script>
<SelectExpand
{label}
bind:value={$locale}
options={$locales.map((value) => ({
label: $t(`lang.${value}`),
value,
selected: value === $locale,
}))}
/>
{label}
bind:value={$locale}
options={$locales.map((value) => ({
label: $t(`lang.${value}`),
value,
selected: value === $locale
}))}
/>

View file

@ -1,39 +1,40 @@
<script lang="ts">
import '$appcss';
export let icon:string;
export let label:string;
import "$appcss";
export let icon: string;
export let label: string;
export let active = false;
export let active = false;
export let count = 0;
export let count = 0;
</script>
<button on:click
class="text-xs w-full flex transition-all rounded-sm hover:bg-opacity-25 border-gray hover:border px-1 gap-2 items-center align-middle text-left hover:bg-gray box-border"
class:active
<button
on:click
class="outline-gray hover:bg-gray box-border flex w-full items-center gap-2 rounded-sm px-1 text-left align-middle text-xs outline-1 transition-all hover:bg-opacity-25 hover:outline"
class:active
>
<i class="icon-{icon} mt-1"/>
<div class="font-thin text-sm">
{label}
{#if count > 0}
<span class="text-right rounded-sm">{count}</span>
{/if}
</div>
<i class="icon-{icon} mt-1" />
<div class="text-sm font-thin">
{label}
{#if count > 0}
<span class="rounded-sm text-right">{count}</span>
{/if}
</div>
</button>
<style>
button {
box-sizing: border-box;
height: 37px;
}
button.active {
background: rgba(148, 148, 148, 0.5);
border: rgba(148, 148, 148, 1) 1px solid;
}
span {
color: white;
background: #FF4100;
padding: 2px;
font-size: 10px;
}
</style>
button {
box-sizing: border-box;
height: 37px;
}
button.active {
background: rgba(148, 148, 148, 0.5);
border: rgba(148, 148, 148, 1) 1px solid;
}
span {
color: white;
background: #ff4100;
padding: 2px;
font-size: 10px;
}
</style>

View file

@ -1,13 +1,12 @@
<script lang="ts">
import '$appcss';
import type { GUIPackage } from '$libs/types';
import type { Package } from '@tea/ui/types';
import { PackageStates } from '$libs/types';
import Preloader from '@tea/ui/Preloader/Preloader.svelte';
import "$appcss";
import type { GUIPackage } from "$libs/types";
import type { Package } from "@tea/ui/types";
import { PackageStates } from "$libs/types";
import Preloader from "@tea/ui/Preloader/Preloader.svelte";
import PackageCard from "$components/packages/package.svelte";
import { onMount } from 'svelte';
import { installPackage } from '@native';
import { packagesStore } from '$libs/stores';
import { onMount } from "svelte";
import { packagesStore } from "$libs/stores";
export let pkg: Package;
@ -27,19 +26,8 @@
<ul class="grid grid-cols-3 bg-black">
{#if packages.length > 0}
{#each packages as pkg}
<div class={pkg.state === PackageStates.INSTALLING ? 'animate-pulse' : ''}>
<PackageCard
{pkg}
onClick={async () => {
try {
pkg.state = PackageStates.INSTALLING;
await installPackage(pkg);
pkg.state = PackageStates.INSTALLED;
} catch (error) {
console.error(error);
}
}}
/>
<div class={pkg.state === PackageStates.INSTALLING ? "animate-pulse" : ""}>
<PackageCard {pkg} />
</div>
{/each}
{:else}

View file

@ -63,7 +63,7 @@
</section>
</div>
{#if $sideNavOpen}
<aside class="border-gray fixed z-50 rounded-md border bg-black transition-all">
<aside class="border-gray fixed z-50 rounded-sm border bg-black transition-all">
<PopoutMenu />
</aside>
{/if}

View file

@ -15,6 +15,6 @@ declare namespace svelte.JSX {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface HTMLAttributes<T> {
onclick_outside: () => void;
leave_delay: () => void;
onleave_delay: () => void;
}
}

View file

@ -1,18 +1,24 @@
export default function mouseLeaveDelay(element: HTMLElement, timeout = 600) {
let isOut = false;
let timeoutId: ReturnType<typeof setTimeout> | null = null;
const handleEnter = () => {
isOut = false;
};
const onDestroy = () => {
element.removeEventListener("mouseenter", handleEnter, true);
element.removeEventListener("mouseleave", handleLeave, true);
element.removeEventListener("mouseenter", handleEnter);
element.removeEventListener("mouseleave", handleLeave);
};
const handleLeave = () => {
isOut = true;
setTimeout(() => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
if (isOut && element) {
element.dispatchEvent(new CustomEvent("leave_delay"));
onDestroy();
@ -20,8 +26,8 @@ export default function mouseLeaveDelay(element: HTMLElement, timeout = 600) {
}, timeout);
};
element.addEventListener("mouseenter", handleEnter, true);
element.addEventListener("mouseleave", handleLeave, true);
element.addEventListener("mouseenter", handleEnter);
element.addEventListener("mouseleave", handleLeave);
return {
destroy: onDestroy

View file

@ -27,12 +27,17 @@
}, 300);
};
const clearInput = () => {
searchInput.value = "";
onSearch("");
return false;
};
onMount(() => {
if (autofocus) searchInput.focus();
Mousetrap.bind(["ctrl+shift+del"], function () {
searchInput.value = "";
return false;
});
Mousetrap.bind(["command+shift+backspace"], clearInput);
Mousetrap.bind(["command+shift+del"], clearInput);
Mousetrap.prototype.stopCallback = () => {
return false;

View file

@ -20,7 +20,7 @@
on:leave_delay={() => unexpand()}
>
<header
class="mt-2 flex h-8 justify-between rounded-sm px-1 hover:border hover:bg-gray focus:bg-secondary"
class="mt-1 flex h-8 items-center justify-between px-1 outline-1 outline-gray hover:bg-gray hover:bg-opacity-25 hover:outline focus:bg-secondary"
>
<span>{label || value}</span>
<i class="icon-downward-arrow mt-1" />
@ -29,7 +29,7 @@
<div class="dropdown pr-2 transition-all">
{#each options as option}
<button
class="flex h-6 w-full items-center justify-between gap-x-1 rounded-sm px-2 text-xs hover:bg-gray"
class="m-[1px] flex h-6 w-full items-center justify-between gap-x-1 px-2 text-xs outline-1 outline-gray hover:bg-gray hover:bg-opacity-25 hover:outline"
on:click={() => (value = option.value)}
>
<div>{option.label}</div>
@ -62,7 +62,9 @@
section.expanded hr {
display: block;
border: 1px solid #272626;
}
section.expanded .dropdown {
max-height: 100px;
overflow-y: scroll;