mirror of
https://github.com/ivabus/gui
synced 2025-06-08 00:00:27 +03:00
#183 render package README.md if exist
This commit is contained in:
parent
6c490fd16c
commit
a33cb2396d
8 changed files with 139 additions and 37 deletions
|
@ -71,6 +71,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/asar": "^3.2.3",
|
"@electron/asar": "^3.2.3",
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
|
"@types/js-yaml": "^4.0.5",
|
||||||
"@vitest/coverage-c8": "^0.27.1",
|
"@vitest/coverage-c8": "^0.27.1",
|
||||||
"axios": "^1.3.2",
|
"axios": "^1.3.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
|
@ -87,7 +88,8 @@
|
||||||
"semver": "^7.3.8",
|
"semver": "^7.3.8",
|
||||||
"svelte-markdown": "^0.2.3",
|
"svelte-markdown": "^0.2.3",
|
||||||
"svelte-watch-resize": "^1.0.3",
|
"svelte-watch-resize": "^1.0.3",
|
||||||
"upath": "^2.0.1"
|
"upath": "^2.0.1",
|
||||||
|
"yaml": "^2.2.1"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
|
|
35
modules/desktop/src/libs/github.ts
Normal file
35
modules/desktop/src/libs/github.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
const yaml = window.require('yaml');
|
||||||
|
|
||||||
|
export async function getGithubOwnerRepo(
|
||||||
|
pkgYamlUrl: string
|
||||||
|
): Promise<{ owner: string; repo: string }> {
|
||||||
|
// https://github.com/teaxyz/pantry.core/blob/main/projects/sqlite.org/package.yml
|
||||||
|
// https://raw.githubusercontent.com/teaxyz/pantry.core/main/projects/sqlite.org/package.yml
|
||||||
|
let owner = '';
|
||||||
|
let repo = '';
|
||||||
|
|
||||||
|
const url = pkgYamlUrl.replace('/github.com', '/raw.githubusercontent.com').replace('/blob', '');
|
||||||
|
|
||||||
|
const { data: rawYaml } = await axios.get(url);
|
||||||
|
|
||||||
|
const data = await yaml.parse(rawYaml);
|
||||||
|
if (data?.versions?.github) {
|
||||||
|
[owner, repo] = data.versions.github.split('/').filter((b: string) => b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
owner,
|
||||||
|
repo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getReadme(owner: string, repo: string): Promise<string> {
|
||||||
|
let readme = '';
|
||||||
|
const req = await axios.get(`https://api.github.com/repos/${owner}/${repo}/readme`);
|
||||||
|
if (req.data?.download_url) {
|
||||||
|
const reqDl = await axios.get(req.data.download_url);
|
||||||
|
readme = reqDl.data;
|
||||||
|
}
|
||||||
|
return readme;
|
||||||
|
}
|
|
@ -2,10 +2,13 @@ import { writable } from 'svelte/store';
|
||||||
import type { GUIPackage } from '../types';
|
import type { GUIPackage } from '../types';
|
||||||
import { getPackages } from '@api';
|
import { getPackages } from '@api';
|
||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
|
import { getPackageBottles } from '@api';
|
||||||
|
|
||||||
|
import { getGithubOwnerRepo, getReadme } from '$libs/github';
|
||||||
|
|
||||||
export default function initPackagesStore() {
|
export default function initPackagesStore() {
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
const { subscribe, set } = writable<GUIPackage[]>([]);
|
const { subscribe, set, update } = writable<GUIPackage[]>([]);
|
||||||
const packages: GUIPackage[] = [];
|
const packages: GUIPackage[] = [];
|
||||||
let packagesIndex: Fuse<GUIPackage>;
|
let packagesIndex: Fuse<GUIPackage>;
|
||||||
|
|
||||||
|
@ -21,6 +24,19 @@ export default function initPackagesStore() {
|
||||||
|
|
||||||
subscribe((v) => packages.push(...v));
|
subscribe((v) => packages.push(...v));
|
||||||
|
|
||||||
|
const updatePackageProp = (full_name: string, props: Partial<GUIPackage>) => {
|
||||||
|
update((pkgs) => {
|
||||||
|
const i = pkgs.findIndex((pkg) => pkg.full_name === full_name);
|
||||||
|
if (i >= 0) {
|
||||||
|
pkgs[i] = {
|
||||||
|
...pkgs[i],
|
||||||
|
...props
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return pkgs;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
packages,
|
packages,
|
||||||
subscribe,
|
subscribe,
|
||||||
|
@ -31,6 +47,44 @@ export default function initPackagesStore() {
|
||||||
const res = packagesIndex.search(term, { limit });
|
const res = packagesIndex.search(term, { limit });
|
||||||
const matchingPackages: GUIPackage[] = res.map((v) => v.item);
|
const matchingPackages: GUIPackage[] = res.map((v) => v.item);
|
||||||
return matchingPackages;
|
return matchingPackages;
|
||||||
|
},
|
||||||
|
subscribeToPackage: (slug: string, cb: (pkg: GUIPackage) => void) => {
|
||||||
|
subscribe((pkgs) => {
|
||||||
|
const foundPackage = pkgs.find((p) => p.slug === slug) as GUIPackage;
|
||||||
|
if (foundPackage) cb(foundPackage);
|
||||||
|
// get readme
|
||||||
|
// get contributors
|
||||||
|
// get github last modified
|
||||||
|
// subscribe((pkgs) => cb(pkgs[pkg]));
|
||||||
|
|
||||||
|
// console.log('f:', foundPackage);
|
||||||
|
// getReadmeRaw('');
|
||||||
|
|
||||||
|
if (!foundPackage.bottles) {
|
||||||
|
getPackageBottles(foundPackage.full_name).then((bottles) => {
|
||||||
|
updatePackageProp(foundPackage.full_name, { bottles });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(foundPackage);
|
||||||
|
if (!foundPackage.readme_md && foundPackage.package_yml_url) {
|
||||||
|
getGithubOwnerRepo(foundPackage.package_yml_url).then(async ({ owner, repo }) => {
|
||||||
|
if (owner && repo) {
|
||||||
|
const readme_md = await getReadme(owner, repo);
|
||||||
|
console.log(readme_md);
|
||||||
|
updatePackageProp(foundPackage.full_name, { readme_md });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getReadmeRaw(owner: string, repo: string): Promise<string> {
|
||||||
|
// const rep = await getRepo('oven-sh', 'bun');
|
||||||
|
// const repo = await octokit.request('GET /repos/{owner}/{repo}', {
|
||||||
|
// owner: '',
|
||||||
|
// repo: '',
|
||||||
|
// });
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
|
@ -26,37 +26,16 @@
|
||||||
let reviews: Review[];
|
let reviews: Review[];
|
||||||
let bottles: Bottle[] = [];
|
let bottles: Bottle[] = [];
|
||||||
let versions: string[] = [];
|
let versions: string[] = [];
|
||||||
|
let readme: string;
|
||||||
|
|
||||||
let tabs: Tab[] = [];
|
let tabs: Tab[] = [];
|
||||||
|
|
||||||
const setPkg = (pkgs: Package[]) => {
|
packagesStore.subscribeToPackage(data?.slug, (p) => {
|
||||||
const foundPackage = pkgs.find(({ slug }) => slug === data?.slug) as Package;
|
pkg = p;
|
||||||
if (!pkg && foundPackage) {
|
if (!bottles.length && pkg.bottles) {
|
||||||
pkg = foundPackage;
|
const newVersion = pkg.bottles.map((b) => b.version);
|
||||||
tabs.push({
|
|
||||||
label: 'details',
|
|
||||||
component: Markdown,
|
|
||||||
props: { pkg }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!reviews && pkg) {
|
|
||||||
packagesReviewStore.subscribe(pkg.full_name, (updatedReviews) => {
|
|
||||||
reviews = updatedReviews;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
packagesStore.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)];
|
versions = [...new Set(newVersion)];
|
||||||
|
bottles.push(...pkg.bottles);
|
||||||
bottles.push(...newBottles);
|
|
||||||
tabs = [
|
tabs = [
|
||||||
...tabs,
|
...tabs,
|
||||||
{
|
{
|
||||||
|
@ -67,10 +46,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
} catch (err) {
|
}
|
||||||
console.error(err);
|
|
||||||
|
if (!readme && pkg.readme_md) {
|
||||||
|
readme = pkg.readme_md;
|
||||||
|
tabs = [
|
||||||
|
{
|
||||||
|
label: 'details',
|
||||||
|
component: Markdown,
|
||||||
|
props: { pkg, source: readme }
|
||||||
|
},
|
||||||
|
...tabs,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
import './styles.css';
|
import './styles.css';
|
||||||
|
|
||||||
// TODO: rm sample
|
// TODO: rm sample
|
||||||
import { md } from './sample';
|
// import { md } from './sample';
|
||||||
|
|
||||||
export let source: string;
|
export let source: string;
|
||||||
|
|
||||||
|
@ -15,5 +15,5 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="markdown-body p-4">
|
<section class="markdown-body p-4">
|
||||||
<SvelteMarkdown source={source || md} {renderers} />
|
<SvelteMarkdown {source} {renderers} />
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Tab } from '../types';
|
import type { Tab } from '../types';
|
||||||
import { onMount } from 'svelte';
|
import { onMount, afterUpdate } from 'svelte';
|
||||||
|
|
||||||
let clazz = '';
|
let clazz = '';
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
let active: string;
|
let active: string;
|
||||||
|
|
||||||
onMount(() => {
|
afterUpdate(() => {
|
||||||
if (tabs.length) {
|
if (tabs.length && !active) {
|
||||||
active = tabs[0].label;
|
active = tabs[0].label;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,6 +19,7 @@ export interface Package {
|
||||||
dl_count: number;
|
dl_count: number;
|
||||||
installs: number;
|
installs: number;
|
||||||
reviews?: Review[];
|
reviews?: Review[];
|
||||||
|
package_yml_url?: string;
|
||||||
// metas
|
// metas
|
||||||
full_description?: string; // probably markdown
|
full_description?: string; // probably markdown
|
||||||
bottles?: Bottle[];
|
bottles?: Bottle[];
|
||||||
|
@ -26,8 +27,9 @@ export interface Package {
|
||||||
size_bytes?: number;
|
size_bytes?: number;
|
||||||
documentation_url?: string;
|
documentation_url?: string;
|
||||||
github_repository_url?: string;
|
github_repository_url?: string;
|
||||||
owners?: Partial<Developer>[];
|
|
||||||
categories?: string[];
|
categories?: string[];
|
||||||
|
contributors?: Contributor[];
|
||||||
|
readme_md?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AirtablePost = {
|
export type AirtablePost = {
|
||||||
|
@ -94,3 +96,9 @@ export type Snippet = {
|
||||||
comment: string;
|
comment: string;
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Contributor = Pick<Developer, 'avatar_url' | 'login' | 'name'> & {
|
||||||
|
github_id: number;
|
||||||
|
developer_id?: string;
|
||||||
|
contributions: number;
|
||||||
|
};
|
||||||
|
|
|
@ -19,6 +19,7 @@ importers:
|
||||||
'@testing-library/jest-dom': ^5.16.5
|
'@testing-library/jest-dom': ^5.16.5
|
||||||
'@testing-library/svelte': ^3.2.2
|
'@testing-library/svelte': ^3.2.2
|
||||||
'@types/bcryptjs': ^2.4.2
|
'@types/bcryptjs': ^2.4.2
|
||||||
|
'@types/js-yaml': ^4.0.5
|
||||||
'@types/testing-library__jest-dom': ^5.14.5
|
'@types/testing-library__jest-dom': ^5.14.5
|
||||||
'@typescript-eslint/eslint-plugin': ^5.27.0
|
'@typescript-eslint/eslint-plugin': ^5.27.0
|
||||||
'@typescript-eslint/parser': ^5.27.0
|
'@typescript-eslint/parser': ^5.27.0
|
||||||
|
@ -62,9 +63,11 @@ importers:
|
||||||
upath: ^2.0.1
|
upath: ^2.0.1
|
||||||
vite: ^4.0.0
|
vite: ^4.0.0
|
||||||
vitest: ^0.28.3
|
vitest: ^0.28.3
|
||||||
|
yaml: ^2.2.1
|
||||||
dependencies:
|
dependencies:
|
||||||
'@electron/asar': 3.2.3
|
'@electron/asar': 3.2.3
|
||||||
'@types/bcryptjs': 2.4.2
|
'@types/bcryptjs': 2.4.2
|
||||||
|
'@types/js-yaml': 4.0.5
|
||||||
'@vitest/coverage-c8': 0.27.1_jsdom@21.0.0
|
'@vitest/coverage-c8': 0.27.1_jsdom@21.0.0
|
||||||
axios: 1.3.2
|
axios: 1.3.2
|
||||||
bcryptjs: 2.4.3
|
bcryptjs: 2.4.3
|
||||||
|
@ -82,6 +85,7 @@ importers:
|
||||||
svelte-markdown: 0.2.3_svelte@3.55.1
|
svelte-markdown: 0.2.3_svelte@3.55.1
|
||||||
svelte-watch-resize: 1.0.3
|
svelte-watch-resize: 1.0.3
|
||||||
upath: 2.0.1
|
upath: 2.0.1
|
||||||
|
yaml: 2.2.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@electron/notarize': 1.2.3
|
'@electron/notarize': 1.2.3
|
||||||
'@playwright/experimental-ct-svelte': 1.29.2_svelte@3.55.1
|
'@playwright/experimental-ct-svelte': 1.29.2_svelte@3.55.1
|
||||||
|
@ -4624,6 +4628,10 @@ packages:
|
||||||
pretty-format: 29.3.1
|
pretty-format: 29.3.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/js-yaml/4.0.5:
|
||||||
|
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/json-schema/7.0.11:
|
/@types/json-schema/7.0.11:
|
||||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -13586,6 +13594,11 @@ packages:
|
||||||
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
/yaml/2.2.1:
|
||||||
|
resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/yargs-parser/20.2.9:
|
/yargs-parser/20.2.9:
|
||||||
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
|
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
Loading…
Reference in a new issue