♻️ Refactor icon picker (#724)

This commit is contained in:
Manuel
2023-02-20 22:11:30 +01:00
committed by GitHub
parent 2c1b329dfd
commit f5686fbf2c
17 changed files with 441 additions and 258 deletions

View File

@@ -0,0 +1,32 @@
export abstract class AbstractIconRepository {
constructor(readonly copyright?: string) {}
async fetch(): Promise<NormalizedIconRepositoryResult> {
try {
return await this.fetchInternally();
} catch (err) {
return {
success: false,
count: 0,
entries: [],
name: '',
copyright: this.copyright,
};
}
}
protected abstract fetchInternally(): Promise<NormalizedIconRepositoryResult>;
}
export type NormalizedIconRepositoryResult = {
name: string;
success: boolean;
count: number;
copyright: string | undefined;
entries: NormalizedIcon[];
};
export type NormalizedIcon = {
url: string;
name: string;
size: number;
};

View File

@@ -0,0 +1,71 @@
import {
AbstractIconRepository,
NormalizedIcon,
NormalizedIconRepositoryResult,
} from './abstract-icons-repository';
export class JsdelivrIconsRepository extends AbstractIconRepository {
static readonly tablerRepository = {
api: 'https://data.jsdelivr.com/v1/packages/gh/walkxcode/dashboard-icons@main?structure=flat',
blob: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons/{0}/{1}',
} as JsdelivrRepositoryUrl;
static readonly papirusRepository = {
api: 'https://data.jsdelivr.com/v1/packages/gh/PapirusDevelopmentTeam/papirus_icons@master?structure=flat',
blob: 'https://cdn.jsdelivr.net/gh/PapirusDevelopmentTeam/papirus_icons/src/{1}',
} as JsdelivrRepositoryUrl;
static readonly homelabSvgAssetsRepository = {
api: 'https://data.jsdelivr.com/v1/packages/gh/loganmarchione/homelab-svg-assets@main?structure=flat',
blob: 'https://cdn.jsdelivr.net/gh/loganmarchione/homelab-svg-assets/assets/{1}',
} as JsdelivrRepositoryUrl;
constructor(
private readonly repository: JsdelivrRepositoryUrl,
private readonly displayName: string,
copyright: string,
) {
super(copyright);
}
protected async fetchInternally(): Promise<NormalizedIconRepositoryResult> {
const response = await fetch(this.repository.api);
const body = (await response.json()) as JsdelivrResponse;
const normalizedEntries = body.files
.filter((file) => !['_banner.png', '_logo.png'].some((x) => file.name.includes(x)))
.filter((file) => ['.png', '.svg'].some((x) => file.name.endsWith(x)))
.map((file): NormalizedIcon => {
const fileNameParts = file.name.split('/');
const fileName = fileNameParts[fileNameParts.length - 1];
const extensions = fileName.split('.')[1];
return {
url: this.repository.blob.replace('{0}', extensions).replace('{1}', fileName),
name: fileName,
size: file.size,
};
});
return {
entries: normalizedEntries,
count: normalizedEntries.length,
success: true,
name: this.displayName,
copyright: this.copyright,
};
}
}
type JsdelivrRepositoryUrl = {
api: string;
blob: string;
};
type JsdelivrResponse = {
files: JsdelivrFile[];
};
type JsdelivrFile = {
name: string;
size: number;
};

View File

@@ -0,0 +1,44 @@
import fs from 'fs';
import {
AbstractIconRepository,
NormalizedIcon,
NormalizedIconRepositoryResult,
} from './abstract-icons-repository';
export class LocalIconsRepository extends AbstractIconRepository {
constructor() {
super('');
}
protected async fetchInternally(): Promise<NormalizedIconRepositoryResult> {
if (!fs.existsSync('./public/icons')) {
return {
count: 0,
entries: [],
name: 'Local',
success: true,
copyright: this.copyright,
};
}
const files = fs.readdirSync('./public/icons');
const normalizedEntries = files
.filter((file) => ['.png', '.svg', '.jpeg', '.jpg'].some((x) => file.endsWith(x)))
.map(
(file): NormalizedIcon => ({
name: file,
url: `./icons/${file}`,
size: 0,
})
);
return {
entries: normalizedEntries,
count: normalizedEntries.length,
success: true,
name: 'Local',
copyright: this.copyright,
};
}
}

View File

@@ -0,0 +1,52 @@
import {
AbstractIconRepository,
NormalizedIcon,
NormalizedIconRepositoryResult,
} from './abstract-icons-repository';
export class UnpkgIconsRepository extends AbstractIconRepository {
static tablerRepository = 'https://unpkg.com/@tabler/icons-png@2.0.0-beta/icons/';
constructor(
private readonly repository: string,
private readonly displayName: string,
copyright: string
) {
super(copyright);
}
protected async fetchInternally(): Promise<NormalizedIconRepositoryResult> {
const response = await fetch(`${this.repository}?meta`);
const body = (await response.json()) as UnpkgResponse;
const normalizedEntries = body.files
.filter((file) => file.type === 'file')
.map((file): NormalizedIcon => {
const fileName = file.path.replace('/icons/', '');
const url = `${this.repository}${fileName}`;
return {
name: fileName,
url,
size: file.size,
};
});
return {
entries: normalizedEntries,
count: normalizedEntries.length,
success: true,
name: this.displayName,
copyright: this.copyright,
};
}
}
type UnpkgResponse = {
files: UnpkgFile[];
};
type UnpkgFile = {
path: string;
type: string;
size: number;
};

View File

@@ -3,7 +3,6 @@ export const dashboardNamespaces = [
'layout/element-selector/selector',
'layout/modals/add-app',
'layout/modals/change-position',
'layout/modals/icon-picker',
'layout/modals/about',
'layout/header/actions/toggle-edit-mode',
'layout/mobile/drawer',