parent
5fc85b610f
commit
8e8e82350d
@ -1,65 +1,76 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const searchProjectsResponse = z.object({
|
||||
hits: z.object({
|
||||
slug: z.string().regex(/^[\w!@$()`.+,"\-']{3,64}$/),
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
categories: z.string().array().default([]),
|
||||
client_side: z.enum(["required", "optional", "unsupported"]),
|
||||
server_side: z.enum(["required", "optional", "unsupported"]),
|
||||
project_type: z.enum(["mod", "modpack", "resourcepack", "shader"]),
|
||||
downloads: z.number(),
|
||||
icon_url: z.string().url(),
|
||||
color: z.number(),
|
||||
project_id: z.string(),
|
||||
author: z.string(),
|
||||
display_categories: z.string().array().default([]),
|
||||
versions: z.string().array(),
|
||||
follows: z.number(),
|
||||
date_created: z.string().datetime({offset: true}),
|
||||
date_modified: z.string().datetime({offset: true}),
|
||||
latest_version: z.string().optional(),
|
||||
license: z.string(),
|
||||
gallery: z.string().array().default([]),
|
||||
featured_gallery: z.string().optional(),
|
||||
}).array(),
|
||||
offset: z.number(),
|
||||
limit: z.number(),
|
||||
total_hits: z.number()
|
||||
export const searchProjectsHit = z.object({
|
||||
slug: z.string().regex(/^[\w!@$()`.+,"\-']{3,64}$/),
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
categories: z.string().array().default([]),
|
||||
client_side: z.enum(['required', 'optional', 'unsupported', 'unknown']),
|
||||
server_side: z.enum(['required', 'optional', 'unsupported', 'unknown']),
|
||||
project_type: z.enum(['mod', 'modpack', 'resourcepack', 'shader']),
|
||||
downloads: z.number(),
|
||||
icon_url: z.union([z.string().url(), z.literal('').transform(() => '/favicon.png')]),
|
||||
color: z.number().nullable(),
|
||||
project_id: z.string(),
|
||||
author: z.string(),
|
||||
display_categories: z.string().array().default([]),
|
||||
versions: z.string().array(),
|
||||
follows: z.number(),
|
||||
date_created: z.string().datetime({ offset: true }),
|
||||
date_modified: z.string().datetime({ offset: true }),
|
||||
latest_version: z.string().optional(),
|
||||
license: z.string(),
|
||||
gallery: z.string().array().default([]),
|
||||
featured_gallery: z.string().nullable()
|
||||
});
|
||||
|
||||
export const searchProjectsResponse = z.object({
|
||||
hits: searchProjectsHit.array(),
|
||||
offset: z.number(),
|
||||
limit: z.number(),
|
||||
total_hits: z.number()
|
||||
});
|
||||
|
||||
const searchProjectsRequest = z.object({
|
||||
query: z.string().optional(),
|
||||
facets: z.string().regex(/^(categories|versions|license|project_type):(.+)$/).array().array().default([]),
|
||||
index: z.enum(["relevance", "downloads", "follows", "newest", "updated"]).default("relevance"),
|
||||
offset: z.number().default(0),
|
||||
limit: z.number().default(10),
|
||||
filters: z.string().optional()
|
||||
query: z.string().optional(),
|
||||
facets: z
|
||||
.string()
|
||||
.regex(/^(categories|versions|license|project_type):(.+)$/)
|
||||
.array()
|
||||
.array()
|
||||
.default([]),
|
||||
index: z.enum(['relevance', 'downloads', 'follows', 'newest', 'updated']).default('relevance'),
|
||||
offset: z.number().default(0),
|
||||
limit: z.number().default(10),
|
||||
filters: z.string().optional()
|
||||
});
|
||||
|
||||
function searchProjectsRequestToUrlParams(request: z.infer<typeof searchProjectsRequest>): URLSearchParams {
|
||||
const params = new URLSearchParams();
|
||||
if (typeof request.query != 'undefined') {
|
||||
params.set("query", request.query);
|
||||
}
|
||||
params.set("facets", JSON.stringify(request.facets));
|
||||
params.set("index", request.index);
|
||||
params.set("offset", request.offset.toString());
|
||||
params.set("limit", request.limit.toString());
|
||||
if (typeof request.filters != 'undefined') {
|
||||
params.set("filters", request.filters);
|
||||
}
|
||||
return params;
|
||||
function searchProjectsRequestToUrlParams(
|
||||
request: z.infer<typeof searchProjectsRequest>
|
||||
): URLSearchParams {
|
||||
const params = new URLSearchParams();
|
||||
if (typeof request.query != 'undefined') {
|
||||
params.set('query', request.query);
|
||||
}
|
||||
params.set('facets', JSON.stringify(request.facets));
|
||||
params.set('index', request.index);
|
||||
params.set('offset', request.offset.toString());
|
||||
params.set('limit', request.limit.toString());
|
||||
if (typeof request.filters != 'undefined') {
|
||||
params.set('filters', request.filters);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
export async function searchProjects(request: z.input<typeof searchProjectsRequest>): Promise<z.infer<typeof searchProjectsResponse>> {
|
||||
const parsedRequest = searchProjectsRequest.parse(request);
|
||||
const params = searchProjectsRequestToUrlParams(parsedRequest);
|
||||
const response = await fetch("https://api.modrinth.com/v2/search?" + params.toString(), {
|
||||
headers: {
|
||||
"User-Agent": "NotModdermore/noversion (+https://git.skye.vg/me/not-moddermore/)"
|
||||
}
|
||||
});
|
||||
return searchProjectsResponse.parse(await response.json());
|
||||
export async function searchProjects(
|
||||
request: z.input<typeof searchProjectsRequest>
|
||||
): Promise<z.infer<typeof searchProjectsResponse>> {
|
||||
const parsedRequest = searchProjectsRequest.parse(request);
|
||||
const params = searchProjectsRequestToUrlParams(parsedRequest);
|
||||
const response = await fetch('https://api.modrinth.com/v2/search?' + params.toString(), {
|
||||
headers: {
|
||||
'User-Agent': 'NotModdermore/noversion (+https://git.skye.vg/me/not-moddermore/)'
|
||||
}
|
||||
});
|
||||
return searchProjectsResponse.parse(await response.json());
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import type { Folder } from '$lib/types';
|
||||
import { DownloadIcon, FileIcon, FolderIcon } from 'svelte-feather-icons';
|
||||
import FileTree from './FileTree.svelte';
|
||||
|
||||
export let tree: Folder;
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
{#each Object.entries(tree.children) as item}
|
||||
<li class="ml-4">
|
||||
{#if item[1].type == 'file'}
|
||||
{#if item[1].inline && item[1].metafile}
|
||||
<DownloadIcon class="inline" />
|
||||
{item[0]}
|
||||
{:else}
|
||||
<FileIcon class="inline" />
|
||||
{item[0]}
|
||||
{/if}
|
||||
{:else}
|
||||
<FolderIcon class="inline" />
|
||||
{item[0]}
|
||||
<FileTree tree={item[1]} />
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
Before Width: | Height: | Size: 633 KiB After Width: | Height: | Size: 285 KiB |
Loading…
Reference in new issue