mirror of
https://github.com/ivabus/gui
synced 2025-06-08 00:00:27 +03:00
Merge pull request #50 from teaxyz/featured-packages
#33 FeaturedPackages component
This commit is contained in:
commit
bca6580127
13 changed files with 202 additions and 15 deletions
|
@ -1,5 +1,8 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
|
globals: {
|
||||||
|
NodeJS: true
|
||||||
|
},
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
||||||
plugins: ['svelte3', '@typescript-eslint'],
|
plugins: ['svelte3', '@typescript-eslint'],
|
||||||
|
|
|
@ -42,7 +42,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^1.2.0",
|
"@tauri-apps/api": "^1.2.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"fuse.js": "^6.6.2"
|
"fuse.js": "^6.6.2",
|
||||||
|
"svelte-watch-resize": "^1.0.3"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import '$appcss';
|
||||||
|
import type { Package } from '@tea/ui/types';
|
||||||
|
export let pkg: Package;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<figure class="w-full h-full relative">
|
||||||
|
<img
|
||||||
|
src={!pkg.thumb_image_url.includes('https://tea.xyz')
|
||||||
|
? 'https://tea.xyz/Images/package-thumb-nolabel4.jpg'
|
||||||
|
: pkg.thumb_image_url}
|
||||||
|
alt={pkg.name}
|
||||||
|
/>
|
||||||
|
<article class="card-thumb-label">
|
||||||
|
<i class="icon-tea-logo-iconasset-1">
|
||||||
|
<!-- TODO: replace with icon.svg -->
|
||||||
|
</i>
|
||||||
|
<h3 class="text-3xl">{pkg.name}</h3>
|
||||||
|
{#if pkg.maintainer}
|
||||||
|
<h4 class="text-lg mt-2">• {pkg.maintainer}</h4>
|
||||||
|
{/if}
|
||||||
|
</article>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
img {
|
||||||
|
box-shadow: 0px 0px 12px #0c0c0c !important;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.card-thumb-label i {
|
||||||
|
font-size: 1.5vw;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-thumb-label h3 {
|
||||||
|
color: black;
|
||||||
|
line-height: 1.8vw;
|
||||||
|
margin: 0px 0px 0.5vw 0vw;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-thumb-label {
|
||||||
|
position: absolute;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
left: 0;
|
||||||
|
bottom: 20px;
|
||||||
|
padding: 1.116vw;
|
||||||
|
text-align: left;
|
||||||
|
min-width: 40%;
|
||||||
|
height: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-thumb-label h4 {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,88 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '$appcss';
|
import '$appcss';
|
||||||
import Placeholder from '$components/Placeholder/Placeholder.svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
|
import { watchResize } from 'svelte-watch-resize';
|
||||||
|
import type { Package } from '@tea/ui/types';
|
||||||
|
import FeaturedPackage from './FeaturedPackage.svelte';
|
||||||
|
import {
|
||||||
|
featuredPackages as featuredPackagesStore,
|
||||||
|
initializeFeaturedPackages
|
||||||
|
} from '$libs/stores';
|
||||||
|
|
||||||
|
let featuredPackages: Package[] = [];
|
||||||
|
|
||||||
|
let pkgFocus = 0;
|
||||||
|
let width = 0;
|
||||||
|
let styleFeaturedPackages: string;
|
||||||
|
|
||||||
|
function resetFeaturedStyle() {
|
||||||
|
const position = pkgFocus * width;
|
||||||
|
styleFeaturedPackages = `
|
||||||
|
width: ${featuredPackages.length * width}px;
|
||||||
|
left: -${position}px;
|
||||||
|
transition: left 0.6s ease-in;
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleContainerResize(node: HTMLElement) {
|
||||||
|
width = node.clientWidth;
|
||||||
|
resetFeaturedStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
let loop: NodeJS.Timer;
|
||||||
|
|
||||||
|
function resetLoop() {
|
||||||
|
if (loop) clearInterval(loop);
|
||||||
|
loop = setInterval(() => {
|
||||||
|
pkgFocus++;
|
||||||
|
if (pkgFocus === featuredPackages.length) {
|
||||||
|
pkgFocus = 0;
|
||||||
|
}
|
||||||
|
resetFeaturedStyle();
|
||||||
|
}, 3000);
|
||||||
|
resetFeaturedStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
featuredPackagesStore.subscribe((v) => {
|
||||||
|
featuredPackages = v;
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => clearInterval(loop));
|
||||||
|
onMount(() => {
|
||||||
|
if (!featuredPackages.length) {
|
||||||
|
initializeFeaturedPackages();
|
||||||
|
}
|
||||||
|
resetLoop();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Placeholder label="FeaturedPackages" />
|
<section class="bg-black w-full h-96" use:watchResize={handleContainerResize}>
|
||||||
|
<!-- <Placeholder label="FeaturedPackages" /> -->
|
||||||
|
<header class="bg-accent h-12 flex justify-between px-2 items-center">
|
||||||
|
<p>FEATURED PACKAGES</p>
|
||||||
|
<ul class="flex gap-2">
|
||||||
|
{#each featuredPackages as pkg, i}
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
pkgFocus = i;
|
||||||
|
resetLoop();
|
||||||
|
}}
|
||||||
|
class={`border-white border-2 w-4 h-4 rounded-lg bg-purple transition-colors ${
|
||||||
|
i === pkgFocus ? 'bg-purple-900' : ''
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
<figure class="overflow-hidden absolute bottom-0 top-12 left-0 right-0">
|
||||||
|
<section class="flex absolute top-0 h-full" style={styleFeaturedPackages}>
|
||||||
|
{#each featuredPackages as pkg}
|
||||||
|
<div class="h-full" style={`width:${width}px`}>
|
||||||
|
<a href={`/packages/${pkg.slug}`}>
|
||||||
|
<FeaturedPackage {pkg} />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</section>
|
||||||
|
</figure>
|
||||||
|
</section>
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
<header class="text-primary text-6xl font-machina uppercase">
|
<header class="text-primary text-6xl font-machina uppercase mb-8">
|
||||||
<slot />
|
<slot />
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -152,3 +152,7 @@ const packages: Package[] = [
|
||||||
export async function getPackages(): Promise<Package[]> {
|
export async function getPackages(): Promise<Package[]> {
|
||||||
return packages;
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getFeaturedPackages(): Promise<Package[]> {
|
||||||
|
return packages.slice(0, 4);
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
import { getClient } from '@tauri-apps/api/http';
|
import { getClient } from '@tauri-apps/api/http';
|
||||||
import { Buffer } from 'buffer';
|
import { Buffer } from 'buffer';
|
||||||
import type { Package } from '../types';
|
import type { Package } from '../types';
|
||||||
|
import * as mock from './mock';
|
||||||
|
|
||||||
const username = 'user';
|
const username = 'user';
|
||||||
const password = 'password';
|
const password = 'password';
|
||||||
|
@ -49,3 +50,8 @@ export async function getPackages(): Promise<Package[]> {
|
||||||
const packages = await get<Package[]>('packages');
|
const packages = await get<Package[]>('packages');
|
||||||
return packages;
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getFeaturedPackages(): Promise<Package[]> {
|
||||||
|
const packages = await mock.getFeaturedPackages();
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
import type { Package } from './types';
|
import type { Package } from './types';
|
||||||
|
|
||||||
import { getPackages } from '@api';
|
import { getPackages, getFeaturedPackages } from '@api';
|
||||||
|
|
||||||
export const backLink = writable<string>('/');
|
export const backLink = writable<string>('/');
|
||||||
|
|
||||||
export const packages = writable<Package[]>([]);
|
export const packages = writable<Package[]>([]);
|
||||||
|
|
||||||
|
export const featuredPackages = writable<Package[]>([]);
|
||||||
|
|
||||||
export const initializePackages = async () => {
|
export const initializePackages = async () => {
|
||||||
const newPackages = await getPackages();
|
const newPackages = await getPackages();
|
||||||
packages.set(newPackages);
|
packages.set(newPackages);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const initializeFeaturedPackages = async () => {
|
||||||
|
const packages = await getFeaturedPackages();
|
||||||
|
featuredPackages.set(packages);
|
||||||
|
};
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
figure {
|
figure {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
top: 180px;
|
top: 220px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
|
|
|
@ -9,18 +9,21 @@
|
||||||
/** @type {import('./$types').PageData} */
|
/** @type {import('./$types').PageData} */
|
||||||
export let data;
|
export let data;
|
||||||
|
|
||||||
import { packages as packagesStore } from '$libs/stores';
|
import { packages, featuredPackages } from '$libs/stores';
|
||||||
|
|
||||||
import type { Package } from '@tea/ui/types';
|
import type { Package } from '@tea/ui/types';
|
||||||
|
|
||||||
let pkg: Package;
|
let pkg: Package;
|
||||||
|
|
||||||
packagesStore.subscribe((allPackages) => {
|
const setPkg = (pkgs: Package[]) => {
|
||||||
const foundPackage = allPackages.find(({ slug }) => slug === data?.slug) as Package;
|
const foundPackage = pkgs.find(({ slug }) => slug === data?.slug) as Package;
|
||||||
if (foundPackage) {
|
if (!pkg && foundPackage) {
|
||||||
pkg = foundPackage;
|
pkg = foundPackage;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
packages.subscribe(setPkg);
|
||||||
|
featuredPackages.subscribe(setPkg);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"paths": {
|
"paths": {
|
||||||
"$appcss": ["src/app.css"],
|
"$appcss": ["src/app.css"],
|
||||||
"$libs/*": ["src/libs/*"],
|
"$libs/*": ["src/libs/*"],
|
||||||
"@api": ["src/lib/api/tauri.ts"],
|
"@api": ["src/libs/api/tauri.ts"],
|
||||||
"$components/*": ["src/components/*"],
|
"$components/*": ["src/components/*"],
|
||||||
"@tea/ui/*": ["../ui/src/*"]
|
"@tea/ui/*": ["../ui/src/*"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
const primary = '#00ffd0';
|
const green = '#00ffd0';
|
||||||
const black = '#1a1a1a';
|
const black = '#1a1a1a';
|
||||||
const white = '#fff';
|
const white = '#fff';
|
||||||
const gray = '#949494';
|
const gray = '#949494';
|
||||||
|
const purple = '#8000FF';
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||||
theme: {
|
theme: {
|
||||||
colors: {
|
colors: {
|
||||||
primary,
|
primary: green,
|
||||||
green: primary,
|
accent: purple,
|
||||||
|
green,
|
||||||
|
purple: {
|
||||||
|
700: purple,
|
||||||
|
900: '#B076EC'
|
||||||
|
},
|
||||||
black,
|
black,
|
||||||
white,
|
white,
|
||||||
gray
|
gray
|
||||||
|
|
|
@ -28,6 +28,7 @@ importers:
|
||||||
svelte: ^3.49.0
|
svelte: ^3.49.0
|
||||||
svelte-check: ^2.8.0
|
svelte-check: ^2.8.0
|
||||||
svelte-preprocess: ^4.10.7
|
svelte-preprocess: ^4.10.7
|
||||||
|
svelte-watch-resize: ^1.0.3
|
||||||
svelte2tsx: ^0.5.20
|
svelte2tsx: ^0.5.20
|
||||||
tailwindcss: ^3.2.4
|
tailwindcss: ^3.2.4
|
||||||
tslib: ^2.3.1
|
tslib: ^2.3.1
|
||||||
|
@ -37,6 +38,7 @@ importers:
|
||||||
'@tauri-apps/api': 1.2.0
|
'@tauri-apps/api': 1.2.0
|
||||||
buffer: 6.0.3
|
buffer: 6.0.3
|
||||||
fuse.js: 6.6.2
|
fuse.js: 6.6.2
|
||||||
|
svelte-watch-resize: 1.0.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@playwright/test': 1.25.0
|
'@playwright/test': 1.25.0
|
||||||
'@sveltejs/adapter-auto': 1.0.0-next.90
|
'@sveltejs/adapter-auto': 1.0.0-next.90
|
||||||
|
@ -4202,6 +4204,10 @@ packages:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/batch-processor/1.0.0:
|
||||||
|
resolution: {integrity: sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/better-opn/2.1.1:
|
/better-opn/2.1.1:
|
||||||
resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==}
|
resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==}
|
||||||
engines: {node: '>8.0.0'}
|
engines: {node: '>8.0.0'}
|
||||||
|
@ -5043,6 +5049,12 @@ packages:
|
||||||
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
|
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/element-resize-detector/1.2.4:
|
||||||
|
resolution: {integrity: sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==}
|
||||||
|
dependencies:
|
||||||
|
batch-processor: 1.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/emoji-regex/8.0.0:
|
/emoji-regex/8.0.0:
|
||||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -9575,6 +9587,12 @@ packages:
|
||||||
typescript: 4.9.3
|
typescript: 4.9.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/svelte-watch-resize/1.0.3:
|
||||||
|
resolution: {integrity: sha512-ktqTnkdqfx4YRqeMJcX1jeSnQ2kJUVlj4/rLdaLbhM+RrxN87vS2EZ0cxlGZ7eXV86Ef05Q3dVqEiR+12PeoIw==}
|
||||||
|
dependencies:
|
||||||
|
element-resize-detector: 1.2.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/svelte/3.53.1:
|
/svelte/3.53.1:
|
||||||
resolution: {integrity: sha512-Q4/hHkktZogGhN5iqxqSi9sjEVoe/NbIxX4hXEHoasTxj+TxEQVAq66LnDMdAZxjmsodkoI5F3slqsS68U7FNw==}
|
resolution: {integrity: sha512-Q4/hHkktZogGhN5iqxqSi9sjEVoe/NbIxX4hXEHoasTxj+TxEQVAq66LnDMdAZxjmsodkoI5F3slqsS68U7FNw==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
Loading…
Reference in a new issue