mirror of
https://github.com/ivabus/gui
synced 2025-06-08 00:00:27 +03:00
Merge pull request #155 from teaxyz/new-package-page-layout
#154 new package page layout
This commit is contained in:
commit
24999a44c8
9 changed files with 121 additions and 16 deletions
|
@ -1,6 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '$appcss';
|
import '$appcss';
|
||||||
import Placeholder from '$components/Placeholder/Placeholder.svelte';
|
import Placeholder from '$components/Placeholder/Placeholder.svelte';
|
||||||
|
|
||||||
|
export let arg1: string;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Placeholder label="Badges" />
|
<Placeholder label="Badges" />
|
||||||
|
<h1>{arg1 || 'tes'}</h1>
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
import type { Package, Bottle } from '@tea/ui/types';
|
import type { Package, Bottle } from '@tea/ui/types';
|
||||||
import Button from '@tea/ui/Button/Button.svelte';
|
import Button from '@tea/ui/Button/Button.svelte';
|
||||||
import StarRating from '@tea/ui/StarRating/StarRating.svelte';
|
import StarRating from '@tea/ui/StarRating/StarRating.svelte';
|
||||||
import Bottles from '@tea/ui/Bottles/Bottles.svelte';
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { getPackageBottles } from '@api';
|
import { getPackageBottles } from '@api';
|
||||||
|
|
||||||
|
@ -33,20 +32,16 @@
|
||||||
<figure class="grow-1 w-1/3">
|
<figure class="grow-1 w-1/3">
|
||||||
<img width={260} src={pkg.thumb_image_url} alt={pkg.full_name} />
|
<img width={260} src={pkg.thumb_image_url} alt={pkg.full_name} />
|
||||||
</figure>
|
</figure>
|
||||||
<article class="w-2/3 p-4">
|
<article class="w-2/3 p-4 pt-8">
|
||||||
<h3 class="text-5xl text-primary">{pkg.full_name}</h3>
|
<h3 class="text-3xl text-primary">{pkg.full_name}</h3>
|
||||||
{#if pkg.maintainer}
|
<h3>• {pkg.maintainer || ''}{pkg.maintainer ? ' |' : ''} {bottles.length} bottles</h3>
|
||||||
<h3>* {pkg.maintainer}</h3>
|
|
||||||
{/if}
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<StarRating maxRating={5} rating={packageRating} />
|
<StarRating maxRating={5} rating={packageRating} />
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-4 font-sono text-sm">{pkg.desc}</p>
|
<p class="mt-4 font-sono text-sm">{pkg.desc}</p>
|
||||||
</article>
|
</article>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
|
||||||
<Bottles {bottles} />
|
|
||||||
</section>
|
|
||||||
<footer class="flex h-20 border-t border-gray text-white">
|
<footer class="flex h-20 border-t border-gray text-white">
|
||||||
<input class="click-copy flex-grow bg-black pl-4" disabled value={copyValue} />
|
<input class="click-copy flex-grow bg-black pl-4" disabled value={copyValue} />
|
||||||
<Button class="w-16 border-0 border-l-2 text-sm" onClick={onCopy}>{copyButtonText}</Button>
|
<Button class="w-16 border-0 border-l-2 text-sm" onClick={onCopy}>{copyButtonText}</Button>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Package } from '@tea/ui/types';
|
||||||
|
export let pkg: Package;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="h-64 w-full">
|
||||||
|
<h1>{pkg.full_name}</h1>
|
||||||
|
</section>
|
|
@ -1,8 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export let coverUrl = '';
|
export let coverUrl = '';
|
||||||
|
let clazz = '';
|
||||||
|
export { clazz as class };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<figure class="relative mb-8 h-32 w-full font-machina uppercase">
|
<figure class={`relative mb-8 h-32 w-full font-machina uppercase ${clazz}`}>
|
||||||
{#if coverUrl}
|
{#if coverUrl}
|
||||||
<img src={coverUrl} class="absolute z-0 h-32 w-full object-cover" alt="cover" />
|
<img src={coverUrl} class="absolute z-0 h-32 w-full object-cover" alt="cover" />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
$: if ($navigating) view.scrollTop = 0;
|
$: if ($navigating) view.scrollTop = 0;
|
||||||
|
|
||||||
afterNavigate(({ from, to }) => {
|
afterNavigate(({ from, to }) => {
|
||||||
if (to?.route.id) {
|
if (to?.route.id && from && from?.url) {
|
||||||
const nextPath = to.url.href.replace(to.url.origin, '');
|
const nextPath = to.url.href.replace(to.url.origin, '');
|
||||||
const fromPath = from?.url.href.replace(from.url.origin, '');
|
const fromPath = from?.url.href.replace(from.url.origin, '');
|
||||||
navStore.setNewPath(nextPath, fromPath || '/');
|
navStore.setNewPath(nextPath, fromPath || '/');
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '$appcss';
|
import '$appcss';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
import PageHeader from '$components/PageHeader/PageHeader.svelte';
|
import PageHeader from '$components/PageHeader/PageHeader.svelte';
|
||||||
import { packagesReviewStore } from '$libs/stores';
|
import { packagesReviewStore } from '$libs/stores';
|
||||||
import PackageBanner from '$components/PackageBanner/PackageBanner.svelte';
|
import PackageBanner from '$components/PackageBanner/PackageBanner.svelte';
|
||||||
import PackageReviews from '$components/PackageReviews/PackageReviews.svelte';
|
import PackageReviews from '$components/PackageReviews/PackageReviews.svelte';
|
||||||
import type { Review } from '@tea/ui/types';
|
import type { Review, Bottle } from '@tea/ui/types';
|
||||||
import SuggestedPackages from '$components/SuggestedPackages/SuggestedPackages.svelte';
|
import SuggestedPackages from '$components/SuggestedPackages/SuggestedPackages.svelte';
|
||||||
|
import Tabs from '@tea/ui/Tabs/Tabs.svelte';
|
||||||
|
import type { Tab } from '@tea/ui/types';
|
||||||
|
import Badges from '$components/Badges/Badges.svelte';
|
||||||
|
import Bottles from '@tea/ui/Bottles/Bottles.svelte';
|
||||||
|
import { getPackageBottles } from '@api';
|
||||||
|
import PackageDetail from '$components/PackageDetail/PackageDetail.svelte';
|
||||||
|
|
||||||
/** @type {import('./$types').PageData} */
|
/** @type {import('./$types').PageData} */
|
||||||
export let data;
|
export let data;
|
||||||
|
@ -17,11 +24,20 @@
|
||||||
let pkg: Package;
|
let pkg: Package;
|
||||||
|
|
||||||
let reviews: Review[];
|
let reviews: Review[];
|
||||||
|
let bottles: Bottle[] = [];
|
||||||
|
let versions: string[] = [];
|
||||||
|
|
||||||
|
let tabs: Tab[] = [];
|
||||||
|
|
||||||
const setPkg = (pkgs: Package[]) => {
|
const setPkg = (pkgs: Package[]) => {
|
||||||
const foundPackage = pkgs.find(({ slug }) => slug === data?.slug) as Package;
|
const foundPackage = pkgs.find(({ slug }) => slug === data?.slug) as Package;
|
||||||
if (!pkg && foundPackage) {
|
if (!pkg && foundPackage) {
|
||||||
pkg = foundPackage;
|
pkg = foundPackage;
|
||||||
|
tabs.push({
|
||||||
|
label: 'details',
|
||||||
|
component: PackageDetail,
|
||||||
|
props: { pkg }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reviews && pkg) {
|
if (!reviews && pkg) {
|
||||||
|
@ -33,17 +49,53 @@
|
||||||
|
|
||||||
packagesStore.subscribe(setPkg);
|
packagesStore.subscribe(setPkg);
|
||||||
featuredPackages.subscribe(setPkg);
|
featuredPackages.subscribe(setPkg);
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
try {
|
||||||
|
const newBottles = await getPackageBottles(pkg.full_name);
|
||||||
|
const newVersion = newBottles.map((b) => b.version);
|
||||||
|
versions = [...new Set(newVersion)];
|
||||||
|
|
||||||
|
bottles.push(...newBottles);
|
||||||
|
console.log('sync tabs:', versions);
|
||||||
|
tabs = [
|
||||||
|
...tabs,
|
||||||
|
{
|
||||||
|
label: `versions (${versions.length || 0})`,
|
||||||
|
component: Bottles,
|
||||||
|
props: {
|
||||||
|
bottles
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
console.log(tabs);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<PageHeader>{pkg.full_name}</PageHeader>
|
<PageHeader coverUrl={pkg.thumb_image_url}>{pkg.full_name}</PageHeader>
|
||||||
<section>
|
<section>
|
||||||
<PackageBanner {pkg} />
|
<PackageBanner {pkg} />
|
||||||
</section>
|
</section>
|
||||||
<section class="mt-8">
|
|
||||||
<PackageReviews reviews={reviews || []} />
|
<section class="mt-8 flex gap-8">
|
||||||
|
<div class="w-2/3 bg-black">
|
||||||
|
<Tabs {tabs} />
|
||||||
|
</div>
|
||||||
|
<div class="h-64 w-1/3 bg-gray">metas</div>
|
||||||
</section>
|
</section>
|
||||||
|
<PageHeader class="mt-8" coverUrl="/images/headers/header_bg_1.png">SNIPPETS</PageHeader>
|
||||||
|
<section class="mt-8 h-64 bg-gray">snippets</section>
|
||||||
|
<!-- <section class="mt-8">
|
||||||
|
<PackageReviews reviews={reviews || []} />
|
||||||
|
</section> -->
|
||||||
{#if pkg}
|
{#if pkg}
|
||||||
|
<PageHeader class="mt-8" coverUrl="/images/headers/header_bg_1.png"
|
||||||
|
>YOU MAY ALSO LIKE...</PageHeader
|
||||||
|
>
|
||||||
<section class="mt-8">
|
<section class="mt-8">
|
||||||
<SuggestedPackages {pkg} />
|
<SuggestedPackages {pkg} />
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button font-sans"
|
type="button"
|
||||||
class={`w-full p-2 font-machina text-gray ${clazz} ${active ? 'active' : ''}`}
|
class={`w-full p-2 font-machina text-gray ${clazz} ${active ? 'active' : ''}`}
|
||||||
on:click={() => onClick && onClick()}
|
on:click={() => onClick && onClick()}
|
||||||
>
|
>
|
||||||
|
|
36
modules/ui/src/Tabs/Tabs.svelte
Normal file
36
modules/ui/src/Tabs/Tabs.svelte
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Tab } from '../types';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
import Button from '../Button/Button.svelte';
|
||||||
|
|
||||||
|
export let tabs: Tab[] = [];
|
||||||
|
|
||||||
|
let active: string;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (tabs.length) {
|
||||||
|
active = tabs[0].label;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('t', tabs);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section class="relative h-auto border border-gray">
|
||||||
|
<menu class="flex border border-gray">
|
||||||
|
{#each tabs as tab}
|
||||||
|
<div class="border border-y-0 border-l-0 border-gray text-white">
|
||||||
|
<Button onClick={() => (active = tab.label)}>
|
||||||
|
<span class={tab.label === active ? 'text-white' : ''}>{tab.label}</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</menu>
|
||||||
|
|
||||||
|
{#each tabs as tab}
|
||||||
|
{#if tab.label === active}
|
||||||
|
<svelte:component this={tab.component} {...tab.props} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</section>
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { ComponentType } from 'svelte';
|
||||||
export interface Review {
|
export interface Review {
|
||||||
title: string;
|
title: string;
|
||||||
comment: string;
|
comment: string;
|
||||||
|
@ -50,3 +51,11 @@ export type Bottle = {
|
||||||
arch: string;
|
arch: string;
|
||||||
version: string;
|
version: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Tab = {
|
||||||
|
label: string;
|
||||||
|
props?: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
component: ComponentType;
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue