Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add UI #61

Merged
merged 2 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/renderer/src/lib/components/AppDetailsPanel.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import { Avatar } from '@skeletonlabs/skeleton';

import { Button } from '$components';

export let imageUrl: string | undefined = undefined;
export let title: string;
export let buttons: Array<string>;
</script>

<div class="bg-app-details-gradient p-8 pb-4">
<div class="flex items-center space-x-4 pb-4">
<Avatar
width="w-20"
src={imageUrl}
initials={title}
fill="fill-current text-white"
background="dark:bg-app-gradient"
rounded="rounded-sm"
/>
<h2 class="text-lg font-bold">{title}</h2>
</div>
{#each buttons as button}
<Button
props={{
type: 'button',
onClick: () => {},
class: 'bg-white/25 rounded-sm px-6 py-2'
}}
>
{button}
</Button>
{/each}
</div>
3 changes: 3 additions & 0 deletions src/renderer/src/lib/components/TopBar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="app-region-drag flex items-center justify-between p-3 dark:bg-apps-input-dark-gradient">
<slot />
</div>
2 changes: 2 additions & 0 deletions src/renderer/src/lib/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export { default as AddTypeModalFooter } from './AddTypeModalFooter.svelte';
export { default as AppDetailsPanel } from './AppDetailsPanel.svelte';
export { default as Button } from './Button.svelte';
export { default as CenterProgressRadial } from './CenterProgressRadial.svelte';
export { default as IconButton } from './IconButton.svelte';
export { default as IconInput } from './IconInput.svelte';
export { default as Input } from './Input.svelte';
export { default as InputWithLabel } from './InputWithLabel.svelte';
export { default as TopBar } from './TopBar.svelte';
10 changes: 9 additions & 1 deletion src/renderer/src/lib/const/launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ export const MODAL_ADD_NEW_HAPP_VERSION = 'modalAddNewHappVersion';
export const SELECTED_ICON_STYLE = 'fill-light-primary dark:fill-white';

export const DEV_PAGE = `${SETTINGS_SCREEN}/dev`;
export const ADD_APP_PAGE = 'add-app';

export const SEARCH_URL_QUERY = 'search';
export const PRESEARCH_URL_QUERY = 'presearch';

export const EMPTY_APP_DATA = {
title: '',
subtitle: '',
description: '',
version: '0.0.1',
icon: undefined as Uint8Array | undefined,
bytes: undefined as Uint8Array | undefined
};
2 changes: 0 additions & 2 deletions src/renderer/src/lib/const/menu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
export const SYSTEM_INFORMATION = 'systemInformation';
export const SYSTEM_SETTINGS = 'systemSettings';

export const VIEW = 'view';
1 change: 1 addition & 0 deletions src/renderer/src/lib/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './display';
export * from './navigation';
export * from './other';
38 changes: 38 additions & 0 deletions src/renderer/src/lib/helpers/navigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { get } from 'svelte/store';

import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { SEARCH_URL_QUERY } from '$const';
import {
ANIMATION_DURATION,
APPS_VIEW,
SEARCH_HEIGH,
WINDOW_SIZE,
WINDOW_SIZE_LARGE
} from '$shared/const';
import type { MainScreenRoute } from '$shared/types';

export const setSearchInput = (event: CustomEvent) => {
const target = event.detail.target;

goto(`?${SEARCH_URL_QUERY}=${target.value}`);
};

export const handleNavigationWithAnimationDelay =
(setInputExpandedFalse: () => void) => (destination: MainScreenRoute) => () => {
setInputExpandedFalse();
setTimeout(() => {
const windowSize =
destination === APPS_VIEW
? { width: WINDOW_SIZE, height: SEARCH_HEIGH }
: { width: WINDOW_SIZE_LARGE, height: WINDOW_SIZE };
window.resizeTo(windowSize.width, windowSize.height);
goto(`/${destination}`);
}, ANIMATION_DURATION);
};

export const goBack = () => {
const { url } = get(page);
const lastSlashIndex = url.pathname.lastIndexOf('/');
goto(url.pathname.substring(0, lastSlashIndex));
};
11 changes: 0 additions & 11 deletions src/renderer/src/lib/helpers/other.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,6 @@ export const validateApp = (app: unknown): app is ExtendedAppInfo =>
export const uint8ArrayToURIComponent = (bytes: Uint8Array) =>
encodeURIComponent(encodeHashToBase64(bytes));

export const getRawQueryParam = (url: string, param: string): string | null => {
const queryString = url.split('?')[1];
if (!queryString) return null;

return (
queryString
.split('&')
.map((pair) => pair.split('='))
.find(([key]) => key === param)?.[1] || null
);
};
export const base64ToArrayBuffer = (base64: string) => {
const binaryString = window.atob(base64);
return new Uint8Array([...binaryString].map((char) => char.charCodeAt(0)));
Expand Down
9 changes: 9 additions & 0 deletions src/renderer/src/lib/icons/BackArrow.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<svg width="16" height="28" viewBox="0 0 16 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M13.6129 26L2 14L13.6129 2"
stroke="white"
stroke-width="4"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
4 changes: 2 additions & 2 deletions src/renderer/src/lib/icons/Warning.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 16C11.8022 16 11.6089 16.0587 11.4445 16.1686C11.28 16.2784 11.1518 16.4346 11.0761 16.6173C11.0005 16.8001 10.9807 17.0011 11.0192 17.1951C11.0578 17.3891 11.1531 17.5673 11.2929 17.7071C11.4328 17.847 11.611 17.9422 11.8049 17.9808C11.9989 18.0194 12.2 17.9996 12.3827 17.9239C12.5654 17.8482 12.7216 17.72 12.8315 17.5556C12.9414 17.3911 13 17.1978 13 17C13 16.7348 12.8947 16.4805 12.7071 16.2929C12.5196 16.1054 12.2652 16 12 16ZM22.67 17.47L14.62 3.47003C14.3598 3.00354 13.9798 2.61498 13.5192 2.3445C13.0586 2.07401 12.5342 1.9314 12 1.9314C11.4659 1.9314 10.9414 2.07401 10.4808 2.3445C10.0202 2.61498 9.64022 3.00354 9.38003 3.47003L1.38003 17.47C1.11082 17.924 0.966171 18.441 0.960673 18.9688C0.955175 19.4966 1.08903 20.0166 1.34871 20.4761C1.6084 20.9356 1.98473 21.3185 2.43971 21.5861C2.89469 21.8536 3.41221 21.9964 3.94003 22H20.06C20.5921 22.0053 21.116 21.8689 21.5779 21.6049C22.0399 21.341 22.4234 20.9589 22.689 20.4978C22.9546 20.0368 23.0929 19.5134 23.0895 18.9814C23.0862 18.4493 22.9414 17.9277 22.67 17.47ZM20.94 19.47C20.8524 19.626 20.7245 19.7556 20.5697 19.8453C20.4149 19.935 20.2389 19.9815 20.06 19.98H3.94003C3.76114 19.9815 3.58513 19.935 3.43035 19.8453C3.27557 19.7556 3.14768 19.626 3.06003 19.47C2.97226 19.318 2.92605 19.1456 2.92605 18.97C2.92605 18.7945 2.97226 18.622 3.06003 18.47L11.06 4.47003C11.1439 4.30623 11.2714 4.16876 11.4285 4.07277C11.5855 3.97678 11.766 3.92599 11.95 3.92599C12.1341 3.92599 12.3146 3.97678 12.4716 4.07277C12.6286 4.16876 12.7561 4.30623 12.84 4.47003L20.89 18.47C20.9892 18.6199 21.0463 18.7937 21.055 18.9732C21.0638 19.1527 21.0241 19.3312 20.94 19.49V19.47ZM12 8.00003C11.7348 8.00003 11.4805 8.10538 11.2929 8.29292C11.1054 8.48046 11 8.73481 11 9.00003V13C11 13.2652 11.1054 13.5196 11.2929 13.7071C11.4805 13.8947 11.7348 14 12 14C12.2652 14 12.5196 13.8947 12.7071 13.7071C12.8947 13.5196 13 13.2652 13 13V9.00003C13 8.73481 12.8947 8.48046 12.7071 8.29292C12.5196 8.10538 12.2652 8.00003 12 8.00003Z"
fill="#FF3A69"
d="M12 16C11.8022 16 11.6088 16.0587 11.4444 16.1686C11.2799 16.2784 11.1518 16.4346 11.0761 16.6173C11.0004 16.8001 10.9806 17.0011 11.0192 17.1951C11.0578 17.3891 11.153 17.5673 11.2929 17.7071C11.4327 17.847 11.6109 17.9422 11.8049 17.9808C11.9989 18.0194 12.1999 17.9996 12.3827 17.9239C12.5654 17.8482 12.7216 17.72 12.8314 17.5556C12.9413 17.3911 13 17.1978 13 17C13 16.7348 12.8946 16.4805 12.7071 16.2929C12.5195 16.1054 12.2652 16 12 16ZM22.67 17.47L14.62 3.47003C14.3598 3.00354 13.9798 2.61498 13.5192 2.3445C13.0586 2.07401 12.5341 1.9314 12 1.9314C11.4658 1.9314 10.9414 2.07401 10.4808 2.3445C10.0202 2.61498 9.64016 3.00354 9.37997 3.47003L1.37997 17.47C1.11076 17.924 0.96611 18.441 0.960612 18.9688C0.955114 19.4966 1.08897 20.0166 1.34865 20.4761C1.60834 20.9356 1.98467 21.3185 2.43965 21.5861C2.89463 21.8536 3.41215 21.9964 3.93997 22H20.06C20.592 22.0053 21.1159 21.8689 21.5779 21.6049C22.0399 21.341 22.4233 20.9589 22.6889 20.4978C22.9546 20.0368 23.0928 19.5134 23.0895 18.9814C23.0861 18.4493 22.9414 17.9277 22.67 17.47ZM20.94 19.47C20.8523 19.626 20.7244 19.7556 20.5697 19.8453C20.4149 19.935 20.2389 19.9815 20.06 19.98H3.93997C3.76108 19.9815 3.58507 19.935 3.43029 19.8453C3.2755 19.7556 3.14762 19.626 3.05997 19.47C2.9722 19.318 2.92599 19.1456 2.92599 18.97C2.92599 18.7945 2.9722 18.622 3.05997 18.47L11.06 4.47003C11.1439 4.30623 11.2714 4.16876 11.4284 4.07277C11.5854 3.97678 11.7659 3.92599 11.95 3.92599C12.134 3.92599 12.3145 3.97678 12.4715 4.07277C12.6286 4.16876 12.7561 4.30623 12.84 4.47003L20.89 18.47C20.9892 18.6199 21.0462 18.7937 21.055 18.9732C21.0638 19.1527 21.0241 19.3312 20.94 19.49V19.47ZM12 8.00003C11.7348 8.00003 11.4804 8.10538 11.2929 8.29292C11.1053 8.48046 11 8.73481 11 9.00003V13C11 13.2652 11.1053 13.5196 11.2929 13.7071C11.4804 13.8947 11.7348 14 12 14C12.2652 14 12.5195 13.8947 12.7071 13.7071C12.8946 13.5196 13 13.2652 13 13V9.00003C13 8.73481 12.8946 8.48046 12.7071 8.29292C12.5195 8.10538 12.2652 8.00003 12 8.00003Z"
fill="#FFB33A"
/>
</svg>
1 change: 1 addition & 0 deletions src/renderer/src/lib/icons/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { default as ArrowLeft } from './ArrowLeft.svelte';
export { default as ArrowRight } from './ArrowRight.svelte';
export { default as BackArrow } from './BackArrow.svelte';
export { default as Check } from './Check.svelte';
export { default as defaultIcon } from './default-icon.png?base64';
export { default as Gear } from './Gear.svelte';
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/src/lib/locale/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"confirmYourPassword": "Confirm your password",
"country": "Country",
"description": "Description",
"details": "Details",
"discoverInstallAndManageYourApps": "Discover, install and manage your apps",
"enterAppName": "Enter app name",
"enterNetworkSeed": "Enter network seed",
Expand Down Expand Up @@ -43,7 +44,7 @@
"open": "Open",
"password": "password",
"passwordPlaceholder": "Enter your password",
"passwordWarning": "Your password can not be reset, recovered or changed. Write it down and store it in a secure location.",
"passwordWarning": "Your password can not be reset, recovered or changed. Save it in your password manager or some other secure location.",
"passwordsDontMatch": "Passwords don't match!",
"region": "Region",
"releases": "Releases",
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/src/lib/modal/AddPublisher.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { goto } from '$app/navigation';
import { AddTypeModalFooter, IconInput } from '$components';
import { ADD_APP_PAGE, DEV_PAGE } from '$const';
import { DEV_PAGE } from '$const';
import { base64ToArrayBuffer } from '$helpers';
import { defaultIcon } from '$icons';
import { createAppQueries } from '$queries';
Expand Down Expand Up @@ -41,7 +41,7 @@
$publisherMutation.mutate(publisherData, {
onSuccess: () => {
modalStore.close();
goto(`/${DEV_PAGE}/${ADD_APP_PAGE}`);
goto(`/${DEV_PAGE}`);
}
});
}}
Expand Down
27 changes: 13 additions & 14 deletions src/renderer/src/lib/queries/happs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
APP_STORE_MY_HAPPS_QUERY_KEY,
PUBLISHERS_QUERY_KEY
} from '$const';
import { uint8ArrayToURIComponent } from '$helpers';
import { getAppStoreClient, getDevHubClient } from '$services';
import {
APP_STORE_CLIENT_NOT_INITIALIZED_ERROR,
Expand Down Expand Up @@ -219,20 +220,18 @@ export const createPublishHappMutation = (queryClient: QueryClient) => {
apphub_hrl_hash: webappPackage.address
});

try {
await appStoreClient.appstoreZomeClient.createAppVersion({
version,
for_app: appEntryEntity.id,
apphub_hrl: {
dna: apphubDnaHash,
target: webappPackageVersion.id
},
apphub_hrl_hash: webappPackageVersion.address,
bundle_hashes: hashes
});
} catch (error) {
console.error(error);
}
await appStoreClient.appstoreZomeClient.createAppVersion({
version,
for_app: appEntryEntity.id,
apphub_hrl: {
dna: apphubDnaHash,
target: webappPackageVersion.id
},
apphub_hrl_hash: webappPackageVersion.address,
bundle_hashes: hashes
});

return uint8ArrayToURIComponent(appEntryEntity.id);
},
onSuccess: () => {
queryClient.invalidateQueries({
Expand Down
121 changes: 117 additions & 4 deletions src/renderer/src/routes/(main)/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,86 @@
import { onMount } from 'svelte';

import { goto } from '$app/navigation';
import { initializeAppPortSubscription } from '$helpers';
import { trpc } from '$services';
import { APPS_VIEW } from '$shared/const';
import { page } from '$app/stores';
import { IconButton, Input, TopBar } from '$components';
import { SEARCH_URL_QUERY, SELECTED_ICON_STYLE } from '$const';
import {
handleNavigationWithAnimationDelay,
initializeAppPortSubscription,
setSearchInput,
validateApp
} from '$helpers';
import { Gear, Home, Rocket } from '$icons';
import { i18n, trpc } from '$services';
import { APP_STORE, APPS_VIEW } from '$shared/const';
import { navigationStore } from '$stores';

const client = trpc();

const hideApp = client.hideApp.createMutation();

const appPort = client.getAppPort.createQuery();
const installedApps = client.getInstalledApps.createQuery();
const openApp = client.openApp.createMutation();

const openSettings = client.openSettings.createMutation();

let inputExpanded = false;

$: searchInput = $page.url.searchParams.get(SEARCH_URL_QUERY) || '';

$: filteredInstalledApps =
$installedApps?.data
?.filter((app) =>
app.appInfo.installed_app_id.toLowerCase().includes(searchInput.toLowerCase())
)
.filter(validateApp) ?? [];

$: type = $page.url.pathname.includes(`/${APP_STORE}/`)
? 'other'
: $page.url.pathname.includes(APP_STORE)
? APP_STORE
: APPS_VIEW;

$: autocomplete =
type === APPS_VIEW && filteredInstalledApps.length > 0
? filteredInstalledApps[0].appInfo.installed_app_id
: '';

$: if (type) inputExpanded = true;

const handleNavigation = handleNavigationWithAnimationDelay(() => (inputExpanded = false));

onMount(() => {
return navigationStore.subscribe((value) => {
if (value !== null) {
handleNavigation(value)();
navigationStore.set(null);
}
});
});

const handlePress = (event: CustomEvent): void => {
if (!(event.detail instanceof KeyboardEvent)) return;

const { key } = event.detail;
const hasApps = filteredInstalledApps.length > 0;

if (key === 'Enter' && type === APPS_VIEW && hasApps && searchInput !== '') {
$openApp.mutate(filteredInstalledApps[0]);
return;
}

if (key === 'Tab' && type === APPS_VIEW) {
event.detail.preventDefault();
goto(`?${SEARCH_URL_QUERY}=${autocomplete}`);
return;
}

if (key === 'Escape' && searchInput !== '') {
event.detail.stopPropagation();
goto(`?${SEARCH_URL_QUERY}=`);
}
};

const handleEscapeKey = (event: KeyboardEvent): void => {
if (event.key === 'Escape') {
Expand All @@ -35,4 +106,46 @@
});
</script>

<TopBar>
{#if type !== APP_STORE}
<IconButton onClick={handleNavigation(APP_STORE)}><Home /></IconButton>
{/if}

<div
class="app-region-no-drag relative mx-2 max-w-md flex-grow origin-left transition-transform"
class:duration-{ANIMATION_DURATION}={inputExpanded}
class:scale-x-100={inputExpanded}
class:scale-x-0={!inputExpanded}
>
<Input
value={searchInput}
bind:autocomplete
on:keydown={handlePress}
on:input={setSearchInput}
props={{
class: 'pl-10 input rounded text-base font-medium',
type: 'text',
placeholder:
type === APP_STORE ? $i18n.t('whatDoYouWantToInstall') : $i18n.t('searchForApps'),
autofocus: true
}}
/>
<div class="absolute left-2 top-2 z-10">
{#if type === APPS_VIEW}
<Rocket fillColor={SELECTED_ICON_STYLE} />
{:else}
<Home fillColor={SELECTED_ICON_STYLE} />
{/if}
</div>
</div>
{#if type !== APPS_VIEW}
<IconButton onClick={handleNavigation(APPS_VIEW)} buttonClass="ml-auto">
<Rocket />
</IconButton>
{/if}
<IconButton onClick={() => $openSettings.mutate(undefined)}>
<Gear />
</IconButton>
</TopBar>

<slot />
23 changes: 0 additions & 23 deletions src/renderer/src/routes/(main)/app-store/+layout.svelte

This file was deleted.

Loading