mirror of
https://github.com/revanced/revanced-website.git
synced 2025-04-30 06:34:35 +02:00
feat: use svelte query (#63)
This commit is contained in:
parent
368b2c9ee5
commit
e1b37fab7d
85
package-lock.json
generated
85
package-lock.json
generated
@ -8,6 +8,10 @@
|
|||||||
"name": "revanced-website",
|
"name": "revanced-website",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "^4.24.4",
|
||||||
|
"@tanstack/query-persist-client-core": "^4.24.4",
|
||||||
|
"@tanstack/query-sync-storage-persister": "^4.24.4",
|
||||||
|
"@tanstack/svelte-query": "^4.24.4",
|
||||||
"asciidoctor": "^2.2.6",
|
"asciidoctor": "^2.2.6",
|
||||||
"marked": "^4.1.1"
|
"marked": "^4.1.1"
|
||||||
},
|
},
|
||||||
@ -624,6 +628,54 @@
|
|||||||
"vite": "^4.0.0"
|
"vite": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tanstack/query-core": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-9dqjv9eeB6VHN7lD3cLo16ZAjfjCsdXetSAD5+VyKqLUvcKTL0CklGQRJu+bWzdrS69R6Ea4UZo8obHYZnG6aA==",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/query-persist-client-core": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-t4BR/th3tu2tkfF0Tcl5z+MbglDjTdIbsLZYlly7l2M6EhGXRjOLbvVUA5Kcx7E2a81Vup0zx0z0wlx+RPGfmg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "4.24.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/query-sync-storage-persister": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-sync-storage-persister/-/query-sync-storage-persister-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-0wffVqoOydMc1TDjOiATv/TM8wJfMpRcM82Cr19TuepListopTsuZ3RzSzLKBCo8WRl/0zCR1Ti9t1zn+Oai/A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-persist-client-core": "4.24.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/svelte-query": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/svelte-query/-/svelte-query-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-B2N+nNPOe9wxZ01i3Ebvkc8vDX9ZDQTiaazXqpld7O27R+zhIBlk6MU8vNzPBDSKrhhl2kak8SwyJOExsVZQXA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "4.24.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": "^3.54.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/cookie": {
|
"node_modules/@types/cookie": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz",
|
||||||
@ -3200,7 +3252,6 @@
|
|||||||
"version": "3.55.0",
|
"version": "3.55.0",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.0.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.0.tgz",
|
||||||
"integrity": "sha512-uGu2FVMlOuey4JoKHKrpZFkoYyj0VLjJdz47zX5+gVK5odxHM40RVhar9/iK2YFRVxvfg9FkhfVlR0sjeIrOiA==",
|
"integrity": "sha512-uGu2FVMlOuey4JoKHKrpZFkoYyj0VLjJdz47zX5+gVK5odxHM40RVhar9/iK2YFRVxvfg9FkhfVlR0sjeIrOiA==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
@ -3990,6 +4041,35 @@
|
|||||||
"vitefu": "^0.2.3"
|
"vitefu": "^0.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@tanstack/query-core": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-9dqjv9eeB6VHN7lD3cLo16ZAjfjCsdXetSAD5+VyKqLUvcKTL0CklGQRJu+bWzdrS69R6Ea4UZo8obHYZnG6aA=="
|
||||||
|
},
|
||||||
|
"@tanstack/query-persist-client-core": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-t4BR/th3tu2tkfF0Tcl5z+MbglDjTdIbsLZYlly7l2M6EhGXRjOLbvVUA5Kcx7E2a81Vup0zx0z0wlx+RPGfmg==",
|
||||||
|
"requires": {
|
||||||
|
"@tanstack/query-core": "4.24.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@tanstack/query-sync-storage-persister": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-sync-storage-persister/-/query-sync-storage-persister-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-0wffVqoOydMc1TDjOiATv/TM8wJfMpRcM82Cr19TuepListopTsuZ3RzSzLKBCo8WRl/0zCR1Ti9t1zn+Oai/A==",
|
||||||
|
"requires": {
|
||||||
|
"@tanstack/query-persist-client-core": "4.24.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@tanstack/svelte-query": {
|
||||||
|
"version": "4.24.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/svelte-query/-/svelte-query-4.24.4.tgz",
|
||||||
|
"integrity": "sha512-B2N+nNPOe9wxZ01i3Ebvkc8vDX9ZDQTiaazXqpld7O27R+zhIBlk6MU8vNzPBDSKrhhl2kak8SwyJOExsVZQXA==",
|
||||||
|
"requires": {
|
||||||
|
"@tanstack/query-core": "4.24.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/cookie": {
|
"@types/cookie": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.1.tgz",
|
||||||
@ -5799,8 +5879,7 @@
|
|||||||
"svelte": {
|
"svelte": {
|
||||||
"version": "3.55.0",
|
"version": "3.55.0",
|
||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.0.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.55.0.tgz",
|
||||||
"integrity": "sha512-uGu2FVMlOuey4JoKHKrpZFkoYyj0VLjJdz47zX5+gVK5odxHM40RVhar9/iK2YFRVxvfg9FkhfVlR0sjeIrOiA==",
|
"integrity": "sha512-uGu2FVMlOuey4JoKHKrpZFkoYyj0VLjJdz47zX5+gVK5odxHM40RVhar9/iK2YFRVxvfg9FkhfVlR0sjeIrOiA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"svelte-check": {
|
"svelte-check": {
|
||||||
"version": "2.10.3",
|
"version": "2.10.3",
|
||||||
|
@ -35,6 +35,10 @@
|
|||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "^4.24.4",
|
||||||
|
"@tanstack/query-persist-client-core": "^4.24.4",
|
||||||
|
"@tanstack/query-sync-storage-persister": "^4.24.4",
|
||||||
|
"@tanstack/svelte-query": "^4.24.4",
|
||||||
"asciidoctor": "^2.2.6",
|
"asciidoctor": "^2.2.6",
|
||||||
"marked": "^4.1.1"
|
"marked": "^4.1.1"
|
||||||
}
|
}
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
import { browser } from '$app/environment';
|
|
||||||
|
|
||||||
import { dev_log } from '$lib/utils';
|
|
||||||
|
|
||||||
const CACHE_KEY_PREFIX = 'revanced_api_cache_l1';
|
|
||||||
const L1_CACHE_VALIDITY = 5 * 60 * 1000; // 5 minutes
|
|
||||||
|
|
||||||
function l1_key_name(endpoint: string) {
|
|
||||||
return `${CACHE_KEY_PREFIX}:${endpoint}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get item from the cache
|
|
||||||
export function get(endpoint: string) {
|
|
||||||
if (!browser) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const key_name = l1_key_name(endpoint);
|
|
||||||
const ls_data: { valid_until: number; data: any } | null = JSON.parse(
|
|
||||||
localStorage.getItem(key_name) as string
|
|
||||||
);
|
|
||||||
|
|
||||||
if (ls_data === null || ls_data.valid_until <= Date.now()) {
|
|
||||||
dev_log('Cache', `missed "${endpoint}"`);
|
|
||||||
localStorage.removeItem(key_name);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_log('Cache', `hit "${endpoint}"`);
|
|
||||||
return ls_data.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the cache
|
|
||||||
export function update(endpoint: string, data: any) {
|
|
||||||
if (!browser) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem(
|
|
||||||
l1_key_name(endpoint),
|
|
||||||
JSON.stringify({
|
|
||||||
data,
|
|
||||||
valid_until: Date.now() + L1_CACHE_VALIDITY
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the cache and reload
|
|
||||||
export function clear_and_reload() {
|
|
||||||
for (const key of Object.keys(localStorage)) {
|
|
||||||
if (key.startsWith(CACHE_KEY_PREFIX)) {
|
|
||||||
localStorage.removeItem(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
location.reload();
|
|
||||||
}
|
|
@ -1,130 +1,24 @@
|
|||||||
import type { Readable, Subscriber, Unsubscriber, Writable } from 'svelte/store';
|
|
||||||
import { writable } from 'svelte/store';
|
|
||||||
import { error } from '@sveltejs/kit';
|
|
||||||
|
|
||||||
import { building, browser, dev } from '$app/environment';
|
|
||||||
|
|
||||||
import * as settings from './settings';
|
import * as settings from './settings';
|
||||||
import * as cache from './cache';
|
|
||||||
|
|
||||||
export class API<T> implements Readable<T> {
|
|
||||||
private store: Writable<T>;
|
|
||||||
// True if we have or are about to request data from the API.
|
|
||||||
has_requested: boolean;
|
|
||||||
|
|
||||||
// `transform` will transform the data received from the API.
|
|
||||||
constructor(
|
|
||||||
public readonly endpoint: string,
|
|
||||||
private readonly default_value: T,
|
|
||||||
private readonly transform: (v: any) => T = (v) => v as T
|
|
||||||
) {
|
|
||||||
// Initialize with cached data if possible.
|
|
||||||
const cached_data = cache.get(this.endpoint);
|
|
||||||
this.has_requested = cached_data !== null;
|
|
||||||
|
|
||||||
this.store = writable(cached_data || this.default_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private url() {
|
|
||||||
return `${settings.api_base_url()}/${this.endpoint}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Please don't call this directly
|
|
||||||
private async _update(fetch_fn: typeof fetch) {
|
|
||||||
// Try to get data from the cache.
|
|
||||||
let data = cache.get(this.endpoint);
|
|
||||||
|
|
||||||
if (data === null) {
|
|
||||||
// Fetch and transform data
|
|
||||||
const response = await fetch_fn(this.url());
|
|
||||||
data = this.transform(await response.json());
|
|
||||||
|
|
||||||
// Update the cache.
|
|
||||||
cache.update(this.endpoint, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.set(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve data and update.
|
|
||||||
private update(fetch_fn = fetch) {
|
|
||||||
// Make sure we set this immediately outside of the async function to avoid JS event loop weirdness.
|
|
||||||
this.has_requested = true;
|
|
||||||
return this._update(fetch_fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start retrieving data if needed.
|
|
||||||
retrieve_if_needed() {
|
|
||||||
if (!this.has_requested) {
|
|
||||||
return this.update();
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements the load function found in `+page/layout.ts` files.
|
|
||||||
page_load_impl() {
|
|
||||||
return async ({ fetch }) => {
|
|
||||||
if (building) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Might be better to actually return some data from the load function and use that on the client.
|
|
||||||
if (!(dev || browser || building)) {
|
|
||||||
throw new Error(
|
|
||||||
'The API client is not optimized for production server-side rendering. Please change that :)'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this.update(fetch);
|
|
||||||
return {};
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
throw error(504, 'API Request Error');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement Svelte store.
|
|
||||||
subscribe(run: Subscriber<T>, invalidate?: any): Unsubscriber {
|
|
||||||
// Make sure we have up-to-date data from the API.
|
|
||||||
if (browser) {
|
|
||||||
this.retrieve_if_needed();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.store.subscribe(run, invalidate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// API Endpoints
|
// API Endpoints
|
||||||
import type { Patch, Repository, Tool } from '../../utils/types';
|
import type { Patch, Repository, Tool } from '$lib/types';
|
||||||
import { dev_log } from '$lib/utils';
|
|
||||||
|
|
||||||
export type ReposData = Repository[];
|
export type ReposData = Repository[];
|
||||||
export type PatchesData = { patches: Patch[]; packages: string[] };
|
export type PatchesData = { patches: Patch[]; packages: string[] };
|
||||||
export type ToolsData = { [repo: string]: Tool };
|
export type ToolsData = { [repo: string]: Tool };
|
||||||
|
|
||||||
export const repositories = new API<ReposData>('contributors', [], (json) => json.repositories);
|
async function get_json(endpoint: string) {
|
||||||
|
const url = `${settings.api_base_url()}/${endpoint}`;
|
||||||
// It needs to look this way to not break everything.
|
return await fetch(url).then((r) => r.json());
|
||||||
const tools_placeholder: ToolsData = {
|
|
||||||
'revanced/revanced-manager': {
|
|
||||||
version: 'v0.0.0',
|
|
||||||
timestamp: '',
|
|
||||||
repository: '',
|
|
||||||
assets: [
|
|
||||||
{
|
|
||||||
url: '',
|
|
||||||
name: '',
|
|
||||||
content_type: '',
|
|
||||||
size: null
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const tools = new API<ToolsData>('tools', tools_placeholder, (json) => {
|
async function repositories(): Promise<ReposData> {
|
||||||
// The API returns data in a weird shape. Make it easier to work with.
|
return await get_json('contributors').then((json) => json.repositories);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tools(): Promise<ToolsData> {
|
||||||
|
const json = await get_json('tools');
|
||||||
|
// Make the data easier to work with.
|
||||||
let map: Map<string, Tool> = new Map();
|
let map: Map<string, Tool> = new Map();
|
||||||
for (const tool of json['tools']) {
|
for (const tool of json['tools']) {
|
||||||
const repo: string = tool.repository;
|
const repo: string = tool.repository;
|
||||||
@ -139,7 +33,7 @@ export const tools = new API<ToolsData>('tools', tools_placeholder, (json) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = map.get(repo);
|
let value = map.get(repo)!!;
|
||||||
value.assets.push({
|
value.assets.push({
|
||||||
name: tool.name,
|
name: tool.name,
|
||||||
size: tool.size,
|
size: tool.size,
|
||||||
@ -151,14 +45,19 @@ export const tools = new API<ToolsData>('tools', tools_placeholder, (json) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Object.fromEntries(map);
|
return Object.fromEntries(map);
|
||||||
});
|
}
|
||||||
|
|
||||||
export const patches = new API<PatchesData>('patches', { patches: [], packages: [] }, (patches) => {
|
async function manager(): Promise<Tool> {
|
||||||
|
return await tools().then((data) => data['revanced/revanced-manager']);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function patches(): Promise<PatchesData> {
|
||||||
|
const json = await get_json('patches');
|
||||||
const packagesWithCount: { [key: string]: number } = {};
|
const packagesWithCount: { [key: string]: number } = {};
|
||||||
|
|
||||||
// gets packages and patch count
|
// gets packages and patch count
|
||||||
for (let i = 0; i < patches.length; i++) {
|
for (let i = 0; i < json.length; i++) {
|
||||||
patches[i].compatiblePackages.forEach((pkg: Patch) => {
|
json[i].compatiblePackages.forEach((pkg: Patch) => {
|
||||||
packagesWithCount[pkg.name] = (packagesWithCount[pkg.name] || 0) + 1;
|
packagesWithCount[pkg.name] = (packagesWithCount[pkg.name] || 0) + 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -168,5 +67,24 @@ export const patches = new API<PatchesData>('patches', { patches: [], packages:
|
|||||||
.sort((a, b) => b[1] - a[1])
|
.sort((a, b) => b[1] - a[1])
|
||||||
.map((pkg) => pkg[0]);
|
.map((pkg) => pkg[0]);
|
||||||
|
|
||||||
return { patches, packages };
|
return { patches: json, packages };
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export const staleTime = 5 * 60 * 1000;
|
||||||
|
export const queries = {
|
||||||
|
manager: {
|
||||||
|
queryKey: ['manager'],
|
||||||
|
queryFn: manager,
|
||||||
|
staleTime
|
||||||
|
},
|
||||||
|
patches: {
|
||||||
|
queryKey: ['patches'],
|
||||||
|
queryFn: patches,
|
||||||
|
staleTime
|
||||||
|
},
|
||||||
|
repositories: {
|
||||||
|
queryKey: ['repositories'],
|
||||||
|
queryFn: repositories,
|
||||||
|
staleTime
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { repositories } from '$data/api';
|
import { queries } from '$data/api';
|
||||||
import { friendlyName } from '$lib/utils';
|
import { friendlyName } from '$lib/utils';
|
||||||
|
|
||||||
|
import { createQuery } from '@tanstack/svelte-query';
|
||||||
|
import Query from '$lib/components/Query.svelte';
|
||||||
|
|
||||||
|
const query = createQuery(['repositories'], queries.repositories);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg aria-hidden="true" width="100%" height="8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg aria-hidden="true" width="100%" height="8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
@ -20,10 +25,11 @@
|
|||||||
<img src="/logo.svg" class="logo-image" alt="ReVanced Logo" />
|
<img src="/logo.svg" class="logo-image" alt="ReVanced Logo" />
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
ReVanced was born out of Vanced's discontinuation and it is our goal to continue the legacy
|
ReVanced was born out of Vanced's discontinuation and it is our goal to continue the
|
||||||
of what Vanced left behind. Thanks to ReVanced Patcher, it's possible to create long-lasting
|
legacy of what Vanced left behind. Thanks to ReVanced Patcher, it's possible to create
|
||||||
patches for nearly any Android app. ReVanced's patching system is designed to allow patches
|
long-lasting patches for nearly any Android app. ReVanced's patching system is designed to
|
||||||
to work on new versions of the apps automatically with bare minimum maintenance.
|
allow patches to work on new versions of the apps automatically with bare minimum
|
||||||
|
maintenance.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -39,23 +45,31 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="link-column">
|
<div class="link-column">
|
||||||
<li>Repositories</li>
|
<li>Repositories</li>
|
||||||
{#each $repositories as { name }}
|
<Query {query} let:data>
|
||||||
|
{#each data as { name }}
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/{name}" target="_blank" rel="noreferrer">
|
<a href="https://github.com/{name}" target="_blank" rel="noreferrer">
|
||||||
{friendlyName(name)}
|
{friendlyName(name)}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
|
</Query>
|
||||||
</div>
|
</div>
|
||||||
<div class="link-column">
|
<div class="link-column">
|
||||||
<!-- to replace -->
|
<!-- to replace -->
|
||||||
<li>Socials</li>
|
<li>Socials</li>
|
||||||
<li><a href="https://github.com/revanced" target="_blank" rel="noreferrer">GitHub</a></li>
|
<li><a href="https://github.com/revanced" target="_blank" rel="noreferrer">GitHub</a></li>
|
||||||
<li><a href="https://revanced.app/discord" target="_blank" rel="noreferrer">Discord</a></li>
|
<li><a href="https://revanced.app/discord" target="_blank" rel="noreferrer">Discord</a></li>
|
||||||
<li><a href="https://reddit.com/r/revancedapp" target="_blank" rel="noreferrer">Reddit</a></li>
|
<li>
|
||||||
|
<a href="https://reddit.com/r/revancedapp" target="_blank" rel="noreferrer">Reddit</a>
|
||||||
|
</li>
|
||||||
<li><a href="https://t.me/app_revanced" target="_blank" rel="noreferrer">Telegram</a></li>
|
<li><a href="https://t.me/app_revanced" target="_blank" rel="noreferrer">Telegram</a></li>
|
||||||
<li><a href="https://twitter.com/revancedapp" target="_blank" rel="noreferrer">Twitter</a></li>
|
<li>
|
||||||
<li><a href="https://www.youtube.com/c/ReVanced" target="_blank" rel="noreferrer">YouTube</a></li>
|
<a href="https://twitter.com/revancedapp" target="_blank" rel="noreferrer">Twitter</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://www.youtube.com/c/ReVanced" target="_blank" rel="noreferrer">YouTube</a>
|
||||||
|
</li>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -66,7 +80,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
footer {
|
footer {
|
||||||
margin: 4rem 0 5rem 0;
|
margin: 4rem 0 5rem 0;
|
||||||
@ -95,7 +108,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#logo-name span {
|
#logo-name span {
|
||||||
color: var(--accent-color)
|
color: var(--accent-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-bottom a {
|
.footer-bottom a {
|
||||||
|
@ -1,9 +1,24 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { queries } from '$data/api';
|
||||||
|
import { dev_log } from '$lib/utils';
|
||||||
|
|
||||||
import RouterEvents from '$data/RouterEvents';
|
import RouterEvents from '$data/RouterEvents';
|
||||||
|
import { useQueryClient } from '@tanstack/svelte-query';
|
||||||
|
const client = useQueryClient();
|
||||||
|
|
||||||
export let href: string;
|
export let href: string;
|
||||||
|
export let queryKey: null | keyof typeof queries = null;
|
||||||
|
|
||||||
|
function prefetch() {
|
||||||
|
if (queryKey !== null) {
|
||||||
|
const query = queries[queryKey];
|
||||||
|
dev_log('Prefetching', query);
|
||||||
|
client.prefetchQuery(query as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a data-sveltekit-preload-data {href}>
|
<a data-sveltekit-preload-data on:mouseenter={prefetch} {href}>
|
||||||
<!-- Check if href is equal to the first path -->
|
<!-- Check if href is equal to the first path -->
|
||||||
<li class:selected={href === '/' + $RouterEvents.target_url.pathname.split('/')[1]}>
|
<li class:selected={href === '/' + $RouterEvents.target_url.pathname.split('/')[1]}>
|
||||||
<span><slot /></span>
|
<span><slot /></span>
|
||||||
|
@ -9,10 +9,21 @@
|
|||||||
import Modal from '$lib/components/Dialogue.svelte';
|
import Modal from '$lib/components/Dialogue.svelte';
|
||||||
import Button from '$lib/components/Button.svelte';
|
import Button from '$lib/components/Button.svelte';
|
||||||
|
|
||||||
import { clear_and_reload } from '$data/api/cache';
|
|
||||||
import * as settings from '$data/api/settings';
|
import * as settings from '$data/api/settings';
|
||||||
import RouterEvents from '$data/RouterEvents';
|
import RouterEvents from '$data/RouterEvents';
|
||||||
|
|
||||||
|
import { useQueryClient } from '@tanstack/svelte-query';
|
||||||
|
|
||||||
|
const client = useQueryClient();
|
||||||
|
|
||||||
|
function clear_and_reload() {
|
||||||
|
client.clear();
|
||||||
|
// `client.clear()` does technically do this for us, but it takes a while.
|
||||||
|
localStorage.clear();
|
||||||
|
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
let url = settings.api_base_url();
|
let url = settings.api_base_url();
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
@ -58,13 +69,13 @@
|
|||||||
<div id="main-navigation">
|
<div id="main-navigation">
|
||||||
<div class="nav-buttons">
|
<div class="nav-buttons">
|
||||||
<Navigation href="/">Home</Navigation>
|
<Navigation href="/">Home</Navigation>
|
||||||
<Navigation href="/download">Download</Navigation>
|
<Navigation queryKey="manager" href="/download">Download</Navigation>
|
||||||
<Navigation href="/patches">Patches</Navigation>
|
<Navigation queryKey="patches" href="/patches">Patches</Navigation>
|
||||||
<div hidden>
|
<div hidden>
|
||||||
<!-- This is just temporary so the build doesn't fail -->
|
<!-- This is just temporary so the build doesn't fail -->
|
||||||
<Navigation href="/docs">Docs</Navigation>
|
<Navigation href="/docs">Docs</Navigation>
|
||||||
</div>
|
</div>
|
||||||
<Navigation href="/contributors">Contributors</Navigation>
|
<Navigation queryKey="repositories" href="/contributors">Contributors</Navigation>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="secondary-navigation">
|
<div id="secondary-navigation">
|
||||||
@ -100,7 +111,9 @@
|
|||||||
</Svg>
|
</Svg>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="title">Settings</svelte:fragment>
|
<svelte:fragment slot="title">Settings</svelte:fragment>
|
||||||
<svelte:fragment slot="description">Configure the website's API. Defaults to ReVanced.</svelte:fragment>
|
<svelte:fragment slot="description"
|
||||||
|
>Configure the website's API. Defaults to ReVanced.</svelte:fragment
|
||||||
|
>
|
||||||
<div id="settings-content">
|
<div id="settings-content">
|
||||||
<div class="input-wrapper">
|
<div class="input-wrapper">
|
||||||
<input name="api-url" type="text" bind:value={url} />
|
<input name="api-url" type="text" bind:value={url} />
|
||||||
|
27
src/lib/components/Query.svelte
Normal file
27
src/lib/components/Query.svelte
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { CreateQueryResult } from '@tanstack/svelte-query';
|
||||||
|
import { isRestoring } from '../../routes/+layout.svelte';
|
||||||
|
// I might try to get this merged into tanstack query.
|
||||||
|
|
||||||
|
// So basically, this is how you do generics here.
|
||||||
|
//https://github.com/sveltejs/language-tools/issues/273#issuecomment-1003496094
|
||||||
|
type T = $$Generic;
|
||||||
|
interface $$Slots {
|
||||||
|
default: {
|
||||||
|
// slot name
|
||||||
|
data: T;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: errors
|
||||||
|
|
||||||
|
export let query: CreateQueryResult<T, any>;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if !$isRestoring}
|
||||||
|
{#if $query.isSuccess}
|
||||||
|
<slot data={$query.data} />
|
||||||
|
{:else if $query.isError}
|
||||||
|
<slot name="error" />
|
||||||
|
{/if}
|
||||||
|
{/if}
|
@ -1,11 +1,44 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
// There might be a better place to put this, but I am not entirely sure...
|
||||||
|
export const isRestoring = writable(false);
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '../app.scss';
|
import '../app.scss';
|
||||||
import { derived } from 'svelte/store';
|
import { derived } from 'svelte/store';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { browser } from '$app/environment';
|
||||||
|
|
||||||
|
import { QueryClient } from '@tanstack/query-core';
|
||||||
|
import { persistQueryClient } from '@tanstack/query-persist-client-core';
|
||||||
|
import { QueryClientProvider } from '@tanstack/svelte-query';
|
||||||
|
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
|
||||||
|
|
||||||
import NavHost from '$layout/Navbar/NavHost.svelte';
|
import NavHost from '$layout/Navbar/NavHost.svelte';
|
||||||
import Spinner from '$lib/components/Spinner.svelte';
|
import Spinner from '$lib/components/Spinner.svelte';
|
||||||
|
import { staleTime } from '$data/api';
|
||||||
import RouterEvents from '$data/RouterEvents';
|
import RouterEvents from '$data/RouterEvents';
|
||||||
|
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
enabled: browser,
|
||||||
|
cacheTime: staleTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
isRestoring.set(true);
|
||||||
|
const [unsubscribe, promise] = persistQueryClient({
|
||||||
|
queryClient,
|
||||||
|
persister: createSyncStoragePersister({ storage: localStorage })
|
||||||
|
});
|
||||||
|
promise.then(() => isRestoring.set(false));
|
||||||
|
return unsubscribe;
|
||||||
|
});
|
||||||
|
|
||||||
// Just like the set/clearInterval example found here: https://svelte.dev/docs#run-time-svelte-store-derived
|
// Just like the set/clearInterval example found here: https://svelte.dev/docs#run-time-svelte-store-derived
|
||||||
const show_loading_animation = derived(
|
const show_loading_animation = derived(
|
||||||
RouterEvents,
|
RouterEvents,
|
||||||
@ -22,6 +55,7 @@
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
<NavHost />
|
<NavHost />
|
||||||
|
|
||||||
{#if $show_loading_animation}
|
{#if $show_loading_animation}
|
||||||
@ -29,7 +63,6 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<slot />
|
<slot />
|
||||||
{/if}
|
{/if}
|
||||||
<!--
|
<!-- guhh afn -->
|
||||||
afn if you are moving the footer here, please make it not use the repositories store directly and instead use component props :) -->
|
<!-- <Footer> -->
|
||||||
|
</QueryClientProvider>
|
||||||
<!-- <Footer repos={$repositories}> -->
|
|
||||||
|
@ -1,14 +1 @@
|
|||||||
import type { PageLoad } from './$types';
|
|
||||||
import { repositories } from '$data/api';
|
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
|
||||||
const base = repositories.page_load_impl();
|
|
||||||
|
|
||||||
export const load: PageLoad = async ({ fetch }) => {
|
|
||||||
// The entire site may softlock if the user sets a bad API url if we don't do this.
|
|
||||||
try {
|
|
||||||
return await base({ fetch });
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@ -2,11 +2,15 @@
|
|||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
|
|
||||||
import { repositories } from '$data/api';
|
|
||||||
|
|
||||||
import ContributorHost from './ContributorSection.svelte';
|
import ContributorHost from './ContributorSection.svelte';
|
||||||
import Footer from '$layout/Footer.svelte';
|
import Footer from '$layout/Footer.svelte';
|
||||||
import Meta from '$lib/components/Meta.svelte';
|
import Meta from '$lib/components/Meta.svelte';
|
||||||
|
import Query from '$lib/components/Query.svelte';
|
||||||
|
|
||||||
|
import { queries } from '$data/api';
|
||||||
|
import { createQuery } from '@tanstack/svelte-query';
|
||||||
|
|
||||||
|
const query = createQuery(['repositories'], queries.repositories);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Meta title="Contributors" />
|
<Meta title="Contributors" />
|
||||||
@ -24,11 +28,13 @@
|
|||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="repos">
|
<div class="repos">
|
||||||
{#each $repositories as { contributors, name: repo }}
|
<Query {query} let:data>
|
||||||
|
{#each data as { contributors, name: repo }}
|
||||||
<div in:fly={{ y: 10, easing: quintOut, duration: 750 }}>
|
<div in:fly={{ y: 10, easing: quintOut, duration: 750 }}>
|
||||||
<ContributorHost {contributors} {repo} />
|
<ContributorHost {contributors} {repo} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
</Query>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
import { repositories } from '$data/api';
|
|
||||||
import type { PageLoad } from './$types';
|
|
||||||
|
|
||||||
export const load: PageLoad = repositories.page_load_impl();
|
|
@ -1,16 +1,19 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { tools } from '$data/api';
|
import { queries } from '$data/api';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
|
|
||||||
|
import { createQuery } from '@tanstack/svelte-query';
|
||||||
|
|
||||||
import manager_screenshot from '$images/manager_two.png?format=avif;webp;png&picture';
|
import manager_screenshot from '$images/manager_two.png?format=avif;webp;png&picture';
|
||||||
|
|
||||||
import Meta from '$lib/components/Meta.svelte';
|
import Meta from '$lib/components/Meta.svelte';
|
||||||
|
import Query from '$lib/components/Query.svelte';
|
||||||
import Button from '$lib/components/Button.svelte';
|
import Button from '$lib/components/Button.svelte';
|
||||||
import Footer from '$layout/Footer.svelte';
|
import Footer from '$layout/Footer.svelte';
|
||||||
import Picture from '$lib/components/Picture.svelte';
|
import Picture from '$lib/components/Picture.svelte';
|
||||||
|
|
||||||
$: manager = $tools['revanced/revanced-manager'];
|
const query = createQuery(['manager'], queries.manager);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Meta title="Download" />
|
<Meta title="Download" />
|
||||||
@ -19,9 +22,11 @@
|
|||||||
<h2>ReVanced <span>Manager</span></h2>
|
<h2>ReVanced <span>Manager</span></h2>
|
||||||
<p>Patch your favourite apps, right on your device.</p>
|
<p>Patch your favourite apps, right on your device.</p>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<Button kind="primary" icon="download" href={manager.assets[0].url} target="_blank">
|
<Query {query} let:data>
|
||||||
{manager.version}
|
<Button kind="primary" icon="download" href={data.assets[0].url} target="_blank">
|
||||||
|
{data.version}
|
||||||
</Button>
|
</Button>
|
||||||
|
</Query>
|
||||||
<Button href="https://github.com/revanced/revanced-manager" target="_blank">View Source</Button>
|
<Button href="https://github.com/revanced/revanced-manager" target="_blank">View Source</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="screenshot">
|
<div class="screenshot">
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
import type { PageLoad } from './$types';
|
|
||||||
|
|
||||||
import { tools } from '$data/api';
|
|
||||||
|
|
||||||
export const load: PageLoad = tools.page_load_impl();
|
|
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import type { Patch } from '$lib/types';
|
import type { Patch } from '$lib/types';
|
||||||
import { patches as api_patches } from '$data/api';
|
|
||||||
|
import { createQuery } from '@tanstack/svelte-query';
|
||||||
|
import { queries } from '$data/api';
|
||||||
|
|
||||||
import Meta from '$lib/components/Meta.svelte';
|
import Meta from '$lib/components/Meta.svelte';
|
||||||
import PackageMenu from '../PackageMenu.svelte';
|
import PackageMenu from '../PackageMenu.svelte';
|
||||||
@ -14,8 +16,9 @@
|
|||||||
import Search from '$lib/components/Search.svelte';
|
import Search from '$lib/components/Search.svelte';
|
||||||
import FilterChip from '$lib/components/FilterChip.svelte';
|
import FilterChip from '$lib/components/FilterChip.svelte';
|
||||||
import Dialogue from '$lib/components/Dialogue.svelte';
|
import Dialogue from '$lib/components/Dialogue.svelte';
|
||||||
|
import Query from '$lib/components/Query.svelte';
|
||||||
|
|
||||||
$: ({ patches, packages } = $api_patches);
|
const query = createQuery(['patches'], queries.patches);
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
$: ({ selectedPkg } = data);
|
$: ({ selectedPkg } = data);
|
||||||
@ -25,24 +28,44 @@
|
|||||||
let timeout: any = null;
|
let timeout: any = null;
|
||||||
let mobilePackages = false;
|
let mobilePackages = false;
|
||||||
|
|
||||||
function filterByPackage(pkg: string | undefined, packageList: any[]) {
|
function checkCompatibility(patch: Patch, pkg: string, cmp: (a: string, b: string) => boolean) {
|
||||||
return packageList.find((x: Package) => x.name === pkg);
|
if (pkg === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !!patch.compatiblePackages.find((compat) => cmp(compat.name, pkg));
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkPkgName(pkg: string, packageList: any[]) {
|
function searchString(str: string, term: string, replacement_regex: RegExp) {
|
||||||
// Basically the same function as before lol
|
return str
|
||||||
return packageList.find((x: Package) => x.name.replace(/\./g, '').includes(pkg));
|
.toLowerCase()
|
||||||
|
.replace(replacement_regex, '')
|
||||||
|
.includes(term || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function search(patch: Patch) {
|
function filter(patches: Patch[], pkg: string, search?: string): Patch[] {
|
||||||
|
if (search === undefined && pkg === '') {
|
||||||
|
return patches;
|
||||||
|
}
|
||||||
|
|
||||||
|
return patches.filter((patch) => {
|
||||||
|
// Don't show if the patch doesn't support the selected package
|
||||||
|
if (pkg && !checkCompatibility(patch, pkg, (a, b) => a === b)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter based on the search term.
|
||||||
|
if (search !== undefined) {
|
||||||
return (
|
return (
|
||||||
patch.description.toLowerCase().replace(/\s/g, '').includes(searchTermFiltered) ||
|
searchString(patch.description, search, /\s/g) ||
|
||||||
patch.name.toLowerCase().replace(/-/g, '').includes(searchTermFiltered) ||
|
searchString(patch.name, search, /-/g) ||
|
||||||
checkPkgName(searchTermFiltered, patch.compatiblePackages)
|
checkCompatibility(patch, pkg, (a, b) => searchString(a, b, /\./g))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure we don't have filter the patches after every key press
|
// Make sure we don't have to filter the patches after every key press
|
||||||
const debounce = () => {
|
const debounce = () => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
@ -83,6 +106,7 @@
|
|||||||
<FilterChip>Patch options</FilterChip> -->
|
<FilterChip>Patch options</FilterChip> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Query {query} let:data>
|
||||||
<div class="mobile-packages-Dialogue">
|
<div class="mobile-packages-Dialogue">
|
||||||
<Dialogue bind:modalOpen={mobilePackages} fullscreen>
|
<Dialogue bind:modalOpen={mobilePackages} fullscreen>
|
||||||
<svelte:fragment slot="title">Packages</svelte:fragment>
|
<svelte:fragment slot="title">Packages</svelte:fragment>
|
||||||
@ -93,7 +117,7 @@
|
|||||||
>
|
>
|
||||||
<Package {selectedPkg} name="All packages" />
|
<Package {selectedPkg} name="All packages" />
|
||||||
</span>
|
</span>
|
||||||
{#each packages as pkg}
|
{#each data.packages as pkg}
|
||||||
<span
|
<span
|
||||||
on:click={() => (mobilePackages = !mobilePackages)}
|
on:click={() => (mobilePackages = !mobilePackages)}
|
||||||
on:keypress={() => (mobilePackages = !mobilePackages)}
|
on:keypress={() => (mobilePackages = !mobilePackages)}
|
||||||
@ -109,7 +133,7 @@
|
|||||||
<PackageMenu>
|
<PackageMenu>
|
||||||
<span class="packages">
|
<span class="packages">
|
||||||
<Package {selectedPkg} name="All packages" />
|
<Package {selectedPkg} name="All packages" />
|
||||||
{#each packages as pkg}
|
{#each data.packages as pkg}
|
||||||
<Package {selectedPkg} name={pkg} />
|
<Package {selectedPkg} name={pkg} />
|
||||||
{/each}
|
{/each}
|
||||||
</span>
|
</span>
|
||||||
@ -117,21 +141,16 @@
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<div class="patches-container">
|
<div class="patches-container">
|
||||||
{#each patches as patch}
|
{#each filter(data.patches, selectedPkg || '', searchTermFiltered) as patch}
|
||||||
<!-- Trigger new animations when package or search changes (I love Svelte) -->
|
<!-- Trigger new animations when package or search changes (I love Svelte) -->
|
||||||
{#key selectedPkg || searchTermFiltered}
|
{#key selectedPkg || searchTermFiltered}
|
||||||
<!-- Show patch if it supports the selected package, or if no package has been selected -->
|
|
||||||
{#if filterByPackage(selectedPkg, patch.compatiblePackages) || !selectedPkg}
|
|
||||||
<!-- ...same with search -->
|
|
||||||
{#if search(patch) || !searchTermFiltered}
|
|
||||||
<div in:fly={{ y: 10, easing: quintOut, duration: 750 }}>
|
<div in:fly={{ y: 10, easing: quintOut, duration: 750 }}>
|
||||||
<PatchItem {patch} />
|
<PatchItem {patch} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
{/key}
|
{/key}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
</Query>
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import { patches } from '$data/api';
|
|
||||||
import type { PageLoad } from './$types';
|
import type { PageLoad } from './$types';
|
||||||
|
|
||||||
const api = patches.page_load_impl();
|
export const load: PageLoad = async ({ params }) => {
|
||||||
|
|
||||||
export const load: PageLoad = async ({ params, fetch }) => {
|
|
||||||
const selectedPkg = params.package || undefined;
|
const selectedPkg = params.package || undefined;
|
||||||
await api({ fetch });
|
|
||||||
return { selectedPkg };
|
return { selectedPkg };
|
||||||
};
|
};
|
||||||
|
@ -10,11 +10,13 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"types": ["node"],
|
"types": ["node"],
|
||||||
|
"lib": ["ESNext", "DOM"],
|
||||||
"paths": {
|
"paths": {
|
||||||
"$data/*": ["./src/data/*"],
|
"$data/*": ["./src/data/*"],
|
||||||
|
"$lib": ["src/lib"],
|
||||||
"$lib/*": ["./src/lib/*"],
|
"$lib/*": ["./src/lib/*"],
|
||||||
"$layout/*": ["./src/layout/*"],
|
"$layout/*": ["./src/layout/*"],
|
||||||
"$images/*": ["./images/*"],
|
"$images/*": ["./images/*"]
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user