Update prettier config + Run pnpm format

This commit is contained in:
venashial
2022-05-26 19:17:15 -07:00
parent 89571d57bd
commit 8d4da009af
62 changed files with 8612 additions and 8618 deletions

View File

@@ -17,4 +17,4 @@ module.exports = {
es2017: true, es2017: true,
node: true, node: true,
}, },
}; }

View File

@@ -1,5 +1,7 @@
{ {
"useTabs": true,
"singleQuote": true, "singleQuote": true,
"printWidth": 100, "printWidth": 100,
"tabWidth": 4 "bracketSameLine": true,
"semi": false
} }

View File

@@ -1,6 +1,6 @@
import { defineMDSveXConfig as defineConfig } from 'mdsvex'; import { defineMDSveXConfig as defineConfig } from 'mdsvex'
import examples from 'mdsvexamples'; import examples from 'mdsvexamples'
import path from 'path'; import path from 'path'
const config = defineConfig({ const config = defineConfig({
extensions: ['.svelte.md', '.md', '.svx'], extensions: ['.svelte.md', '.md', '.svx'],
@@ -24,6 +24,6 @@ const config = defineConfig({
layout: { layout: {
_: './src/docs/layout/page.svelte', _: './src/docs/layout/page.svelte',
}, },
}); })
export default config; export default config

View File

@@ -1,58 +1,55 @@
import { ComponentParser } from 'sveld'; import { ComponentParser } from 'sveld'
import * as svelte from 'svelte/compiler'; import * as svelte from 'svelte/compiler'
import fs from 'fs/promises'; import fs from 'fs/promises'
import path from 'path'; import path from 'path'
import { preprocess } from '../src/package/config/svelte.config.js'; import { preprocess } from '../src/package/config/svelte.config.js'
export default function sveld() { export default function sveld() {
return { return {
name: 'vite-plugin-sveld', name: 'vite-plugin-sveld',
async transform(src, id) { async transform(src, id) {
if (id.endsWith('?raw&sveld')) { if (id.endsWith('?raw&sveld')) {
const raw = JSON.parse(src.split('export default ')[1]); const raw = JSON.parse(src.split('export default ')[1])
const data = await parseRaw(raw, id); const data = await parseRaw(raw, id)
return { return {
code: `export default ${JSON.stringify(data)}`, code: `export default ${JSON.stringify(data)}`,
map: null, map: null,
}; }
} }
}, },
// This generates a `COMPONENT_API.json` with sveld in the `/_app` folder on build, which is used by the docs about components (only when built statically) // This generates a `COMPONENT_API.json` with sveld in the `/_app` folder on build, which is used by the docs about components (only when built statically)
async buildStart() { async buildStart() {
const output = {}; const output = {}
const componentFiles = await fs.readdir(path.resolve('./src/package/components')); const componentFiles = await fs.readdir(path.resolve('./src/package/components'))
for (const fileName of componentFiles.filter((name) => name.endsWith('.svelte'))) { for (const fileName of componentFiles.filter((name) => name.endsWith('.svelte'))) {
const filePath = path.resolve('./src/package/components', fileName); const filePath = path.resolve('./src/package/components', fileName)
const raw = (await fs.readFile(filePath)).toString(); const raw = (await fs.readFile(filePath)).toString()
output[fileName] = await parseRaw(raw, filePath); output[fileName] = await parseRaw(raw, filePath)
} }
try { try {
await fs.mkdir(path.resolve('./src/generated')); await fs.mkdir(path.resolve('./src/generated'))
} catch { } catch {
// Do nothing, directory already exists // Do nothing, directory already exists
} }
await fs.writeFile( await fs.writeFile(path.resolve('./src/generated/COMPONENT_API.json'), JSON.stringify(output))
path.resolve('./src/generated/COMPONENT_API.json'),
JSON.stringify(output)
);
}, },
}; }
} }
async function parseRaw(raw, filePath) { async function parseRaw(raw, filePath) {
let { code } = await svelte.preprocess(raw, preprocess, { let { code } = await svelte.preprocess(raw, preprocess, {
filename: filePath, filename: filePath,
}); })
return new ComponentParser({ return new ComponentParser({
verbose: false, verbose: false,
}).parseSvelteComponent(code, { }).parseSvelteComponent(code, {
filePath, filePath,
moduleName: filePath, moduleName: filePath,
}); })
} }

View File

@@ -1 +1 @@
module.exports = require('./src/package/config/postcss.config.cjs'); module.exports = require('./src/package/config/postcss.config.cjs')

6
src/global.d.ts vendored
View File

@@ -1,8 +1,8 @@
/// <reference types="vite-plugin-sveld" /> /// <reference types="vite-plugin-sveld" />
declare module '$assets/images/*'; declare module '$assets/images/*'
declare module '$locales/*'; declare module '$locales/*'
declare module '*.svg' { declare module '*.svg' {
export { SvelteComponentDev as default } from 'svelte/internal'; export { SvelteComponentDev as default } from 'svelte/internal'
} }

View File

@@ -1,8 +1,8 @@
import type { SvelteComponentDev } from 'svelte/internal'; import type { SvelteComponentDev } from 'svelte/internal'
export interface Option { export interface Option {
label: string; label: string
/** The element that will be in the `value` array while the option is checked */ /** The element that will be in the `value` array while the option is checked */
value: string | number; value: string | number
icon?: SvelteComponentDev | string; icon?: SvelteComponentDev | string
} }

View File

@@ -28,6 +28,6 @@ const config = {
preset: 'default', preset: 'default',
}), }),
], ],
}; }
module.exports = config; module.exports = config

View File

@@ -1,11 +1,11 @@
import sveltePreprocess from 'svelte-preprocess'; import sveltePreprocess from 'svelte-preprocess'
import Icons from 'unplugin-icons/vite'; import Icons from 'unplugin-icons/vite'
import svelteSvg from '@poppanator/sveltekit-svg'; import svelteSvg from '@poppanator/sveltekit-svg'
export const preprocess = sveltePreprocess({ export const preprocess = sveltePreprocess({
postcss: true, postcss: true,
preserve: ['ld+json'], preserve: ['ld+json'],
}); })
export const plugins = [ export const plugins = [
svelteSvg(), svelteSvg(),
@@ -14,4 +14,4 @@ export const plugins = [
defaultClass: 'icon', defaultClass: 'icon',
scale: 1, scale: 1,
}), }),
]; ]

View File

@@ -1,25 +1,25 @@
/* COMPONENTS */ /* COMPONENTS */
export { default as Avatar } from './components/Avatar.svelte'; export { default as Avatar } from './components/Avatar.svelte'
export { default as Badge } from './components/Badge.svelte'; export { default as Badge } from './components/Badge.svelte'
export { default as Button } from './components/Button.svelte'; export { default as Button } from './components/Button.svelte'
export { default as Checkbox } from './components/Checkbox.svelte'; export { default as Checkbox } from './components/Checkbox.svelte'
export { default as CheckboxList } from './components/CheckboxList.svelte'; export { default as CheckboxList } from './components/CheckboxList.svelte'
export { default as CheckboxVirtualList } from './components/CheckboxVirtualList.svelte'; export { default as CheckboxVirtualList } from './components/CheckboxVirtualList.svelte'
export { default as Chips } from './components/Chips.svelte'; export { default as Chips } from './components/Chips.svelte'
export { default as FormField } from './components/FormField.svelte'; export { default as FormField } from './components/FormField.svelte'
export { default as NavRow } from './components/NavRow.svelte'; export { default as NavRow } from './components/NavRow.svelte'
export { default as Pagination } from './components/Pagination.svelte'; export { default as Pagination } from './components/Pagination.svelte'
export { default as Select } from './components/Select.svelte'; export { default as Select } from './components/Select.svelte'
export { default as Slider } from './components/Slider.svelte'; export { default as Slider } from './components/Slider.svelte'
export { default as TextInput } from './components/TextInput.svelte'; export { default as TextInput } from './components/TextInput.svelte'

View File

@@ -1,10 +1,10 @@
export default function Generator(options: PluginOptions): { export default function Generator(options: PluginOptions): {
name: string; name: string
buildStart(): Promise<void>; buildStart(): Promise<void>
}; }
export interface PluginOptions { export interface PluginOptions {
projectColors: boolean; projectColors: boolean
landingPage: boolean; landingPage: boolean
gameVersions: boolean; gameVersions: boolean
tags: boolean; tags: boolean
} }

View File

@@ -1,27 +1,27 @@
import { promises as fs } from 'fs'; import { promises as fs } from 'fs'
import { landingPage } from './outputs/landingPage.js'; import { landingPage } from './outputs/landingPage.js'
import { projectColors } from './outputs/projectColors.js'; import { projectColors } from './outputs/projectColors.js'
import { gameVersions } from './outputs/gameVersions.js'; import { gameVersions } from './outputs/gameVersions.js'
import { tags } from './outputs/tags.js'; import { tags } from './outputs/tags.js'
const API_URL = const API_URL =
process.env.VITE_API_URL && process.env.VITE_API_URL === 'https://staging-api.modrinth.com/v2/' process.env.VITE_API_URL && process.env.VITE_API_URL === 'https://staging-api.modrinth.com/v2/'
? 'https://staging-api.modrinth.com/v2/' ? 'https://staging-api.modrinth.com/v2/'
: 'https://api.modrinth.com/v2/'; : 'https://api.modrinth.com/v2/'
// Time to live: 7 days // Time to live: 7 days
const TTL = 7 * 24 * 60 * 60 * 1000; const TTL = 7 * 24 * 60 * 60 * 1000
export default function Generator(options) { export default function Generator(options) {
return { return {
name: 'rollup-plugin-omorphia-generator', name: 'rollup-plugin-omorphia-generator',
async buildStart() { async buildStart() {
let state = {}; let state = {}
try { try {
state = JSON.parse(await fs.readFile('./generated/state.json', 'utf8')); state = JSON.parse(await fs.readFile('./generated/state.json', 'utf8'))
} catch { } catch {
// File doesn't exist, create folder // File doesn't exist, create folder
await fs.mkdir('./generated', { recursive: true }); await fs.mkdir('./generated', { recursive: true })
await fs.writeFile( await fs.writeFile(
'./generated/state.json', './generated/state.json',
JSON.stringify( JSON.stringify(
@@ -31,7 +31,7 @@ export default function Generator(options) {
null, null,
2 2
) )
); )
} }
// Don't generate if the last generation was less than TTL and the options are the same // Don't generate if the last generation was less than TTL and the options are the same
@@ -40,19 +40,19 @@ export default function Generator(options) {
new Date(state.lastGenerated).getTime() + TTL > new Date().getTime() && new Date(state.lastGenerated).getTime() + TTL > new Date().getTime() &&
JSON.stringify(state.options) === JSON.stringify(options) JSON.stringify(state.options) === JSON.stringify(options)
) { ) {
return; return
} }
if (options.tags) await tags(API_URL); if (options.tags) await tags(API_URL)
if (options.landingPage) await landingPage(API_URL); if (options.landingPage) await landingPage(API_URL)
if (options.gameVersions) await gameVersions(API_URL); if (options.gameVersions) await gameVersions(API_URL)
if (options.projectColors) await projectColors(API_URL); if (options.projectColors) await projectColors(API_URL)
// Write new state // Write new state
state.lastGenerated = new Date().toISOString(); state.lastGenerated = new Date().toISOString()
state.options = options; state.options = options
await fs.writeFile('./generated/state.json', JSON.stringify(state, null, 2)); await fs.writeFile('./generated/state.json', JSON.stringify(state, null, 2))
}, },
}; }
} }

View File

@@ -1 +1 @@
export declare function gameVersions(API_URL: string): Promise<void>; export declare function gameVersions(API_URL: string): Promise<void>

View File

@@ -1,6 +1,6 @@
import { fetch } from 'undici'; import { fetch } from 'undici'
import { promises as fs } from 'fs'; import { promises as fs } from 'fs'
import cliProgress from 'cli-progress'; import cliProgress from 'cli-progress'
export async function gameVersions(API_URL) { export async function gameVersions(API_URL) {
const progressBar = new cliProgress.SingleBar({ const progressBar = new cliProgress.SingleBar({
@@ -8,15 +8,15 @@ export async function gameVersions(API_URL) {
barCompleteChar: '\u2588', barCompleteChar: '\u2588',
barIncompleteChar: '\u2591', barIncompleteChar: '\u2591',
hideCursor: true, hideCursor: true,
}); })
progressBar.start(2, 0); progressBar.start(2, 0)
const gameVersions = await (await fetch(API_URL + 'tag/game_version')).json(); const gameVersions = await (await fetch(API_URL + 'tag/game_version')).json()
progressBar.increment(); progressBar.increment()
// Write JSON file // Write JSON file
await fs.writeFile('./generated/gameVersions.json', JSON.stringify(gameVersions)); await fs.writeFile('./generated/gameVersions.json', JSON.stringify(gameVersions))
progressBar.increment(); progressBar.increment()
progressBar.stop(); progressBar.stop()
} }

View File

@@ -1 +1 @@
export declare function landingPage(API_URL: string): Promise<void>; export declare function landingPage(API_URL: string): Promise<void>

View File

@@ -1,6 +1,6 @@
import { fetch } from 'undici'; import { fetch } from 'undici'
import { promises as fs } from 'fs'; import { promises as fs } from 'fs'
import cliProgress from 'cli-progress'; import cliProgress from 'cli-progress'
export async function landingPage(API_URL) { export async function landingPage(API_URL) {
const progressBar = new cliProgress.SingleBar({ const progressBar = new cliProgress.SingleBar({
@@ -8,25 +8,25 @@ export async function landingPage(API_URL) {
barCompleteChar: '\u2588', barCompleteChar: '\u2588',
barIncompleteChar: '\u2591', barIncompleteChar: '\u2591',
hideCursor: true, hideCursor: true,
}); })
progressBar.start(100, 0); progressBar.start(100, 0)
// Fetch top 100 mods // Fetch top 100 mods
const response = await ( const response = await (
await fetch(API_URL + 'search?limit=100&facets=[["project_type:mod"]]') await fetch(API_URL + 'search?limit=100&facets=[["project_type:mod"]]')
).json(); ).json()
// Simplified array with the format: ['id', 'slug', 'icon_extension'] // Simplified array with the format: ['id', 'slug', 'icon_extension']
const compressed = response.hits const compressed = response.hits
.filter((project) => project.icon_url) .filter((project) => project.icon_url)
.map((project) => { .map((project) => {
progressBar.increment(); progressBar.increment()
return [ return [
project.project_id, project.project_id,
project.slug || '', project.slug || '',
project.icon_url.match(/\.[0-9a-z]+$/i)[0].substring(1), project.icon_url.match(/\.[0-9a-z]+$/i)[0].substring(1),
]; ]
}); })
// Write JSON file // Write JSON file
await fs.writeFile( await fs.writeFile(
@@ -35,6 +35,6 @@ export async function landingPage(API_URL) {
mods: compressed, mods: compressed,
random: Math.random(), random: Math.random(),
}) })
); )
progressBar.stop(); progressBar.stop()
} }

View File

@@ -1 +1 @@
export declare function projectColors(API_URL: string): Promise<void>; export declare function projectColors(API_URL: string): Promise<void>

View File

@@ -1,8 +1,8 @@
import { fetch } from 'undici'; import { fetch } from 'undici'
import { promises as fs, createWriteStream } from 'fs'; import { promises as fs, createWriteStream } from 'fs'
import cliProgress from 'cli-progress'; import cliProgress from 'cli-progress'
import Jimp from 'jimp'; import Jimp from 'jimp'
import { getAverageColor } from 'fast-average-color-node'; import { getAverageColor } from 'fast-average-color-node'
// Note: This function has issues and will occasionally fail with some project icons. It averages at a 99.4% success rate. Most issues are from ECONNRESET errors & Jimp not being able to handle webp & svg images. // Note: This function has issues and will occasionally fail with some project icons. It averages at a 99.4% success rate. Most issues are from ECONNRESET errors & Jimp not being able to handle webp & svg images.
export async function projectColors(API_URL) { export async function projectColors(API_URL) {
@@ -11,22 +11,22 @@ export async function projectColors(API_URL) {
barCompleteChar: '\u2588', barCompleteChar: '\u2588',
barIncompleteChar: '\u2591', barIncompleteChar: '\u2591',
hideCursor: true, hideCursor: true,
}); })
// Get total number of projects // Get total number of projects
const projectCount = (await (await fetch(API_URL + 'search?limit=0')).json()).total_hits; const projectCount = (await (await fetch(API_URL + 'search?limit=0')).json()).total_hits
progressBar.start(projectCount, 0); progressBar.start(projectCount, 0)
const writeStream = createWriteStream('./generated/projects.json'); const writeStream = createWriteStream('./generated/projects.json')
writeStream.write('{'); writeStream.write('{')
// Used to form the JSON string (so that the first doesn't have a comma prefix) // Used to form the JSON string (so that the first doesn't have a comma prefix)
let first = true; let first = true
let completed = 0; let completed = 0
// Number of pages through search to fetch // Number of pages through search to fetch
const requestCount = Math.ceil(projectCount / 100); const requestCount = Math.ceil(projectCount / 100)
await Promise.allSettled( await Promise.allSettled(
Array.from({ length: requestCount }, async (_, index) => { Array.from({ length: requestCount }, async (_, index) => {
const response = await fetch(API_URL + `search?limit=100&offset=${index * 100}`); const response = await fetch(API_URL + `search?limit=100&offset=${index * 100}`)
if (!response.ok) { if (!response.ok) {
throw new Error(`Failed to fetch projects: ${response.statusText}`); throw new Error(`Failed to fetch projects: ${response.statusText}`)
} }
// Get project hits & use map to get rid of extra data // Get project hits & use map to get rid of extra data
const hits = (await response.json()).hits.map((project) => ({ const hits = (await response.json()).hits.map((project) => ({
@@ -34,7 +34,7 @@ export async function projectColors(API_URL) {
slug: project.slug, slug: project.slug,
title: project.title, title: project.title,
icon_url: project.icon_url, icon_url: project.icon_url,
})); }))
// Try parsing the icon of each project // Try parsing the icon of each project
await Promise.allSettled( await Promise.allSettled(
hits.map(async (project) => { hits.map(async (project) => {
@@ -47,40 +47,40 @@ export async function projectColors(API_URL) {
try { try {
const image = await Jimp.read( const image = await Jimp.read(
project.icon_url.replace('cdn', 'cdn-raw') // Skip redirect to raw CDN project.icon_url.replace('cdn', 'cdn-raw') // Skip redirect to raw CDN
); )
// Resize image before getting average color (faster) // Resize image before getting average color (faster)
image.resize(256, 256); image.resize(256, 256)
// Get bottom edge of image // Get bottom edge of image
const edge = image.clone().crop(0, 255, 256, 1); const edge = image.clone().crop(0, 255, 256, 1)
const buffer = await edge.getBufferAsync(Jimp.AUTO); const buffer = await edge.getBufferAsync(Jimp.AUTO)
let color = (await getAverageColor(buffer)).hexa; let color = (await getAverageColor(buffer)).hexa
// If the edge is transparent, use the average color of the entire image // If the edge is transparent, use the average color of the entire image
if (color === '#00000000') { if (color === '#00000000') {
const buffer = await image.getBufferAsync(Jimp.AUTO); const buffer = await image.getBufferAsync(Jimp.AUTO)
color = (await getAverageColor(buffer)).hexa; color = (await getAverageColor(buffer)).hexa
} }
// Remove color transparency // Remove color transparency
color = color.replace(/.{2}$/, ''); color = color.replace(/.{2}$/, '')
// Only use comma prefix if not first // Only use comma prefix if not first
let prefix = ','; let prefix = ','
if (first) { if (first) {
prefix = ''; prefix = ''
first = false; first = false
} }
writeStream.write(`${prefix}"${project.project_id}":"${color}"`); writeStream.write(`${prefix}"${project.project_id}":"${color}"`)
completed++; completed++
} catch (error) { } catch (error) {
// Ignore errors // Ignore errors
// console.log(error); // console.log(error);
} }
} }
progressBar.increment(); progressBar.increment()
}) })
); )
}) })
); )
writeStream.write('}'); writeStream.write('}')
writeStream.end(); writeStream.end()
progressBar.stop(); progressBar.stop()
console.log(`Failed to parse ${projectCount - completed} project icons.`); console.log(`Failed to parse ${projectCount - completed} project icons.`)
} }

View File

@@ -1 +1 @@
export declare function tags(API_URL: string): Promise<void>; export declare function tags(API_URL: string): Promise<void>

View File

@@ -1,14 +1,14 @@
import { fetch } from 'undici'; import { fetch } from 'undici'
import { promises as fs } from 'fs'; import { promises as fs } from 'fs'
import cliProgress from 'cli-progress'; import cliProgress from 'cli-progress'
export async function tags(API_URL) { export async function tags(API_URL) {
const progressBar = new cliProgress.SingleBar({ const progressBar = new cliProgress.SingleBar({
format: 'Generating tags | {bar} | {percentage}%', format: 'Generating tags | {bar} | {percentage}%',
barCompleteChar: '\u2588', barCompleteChar: '\u2588',
barIncompleteChar: '\u2591', barIncompleteChar: '\u2591',
hideCursor: true, hideCursor: true,
}); })
progressBar.start(7, 0); progressBar.start(7, 0)
// eslint-disable-next-line prefer-const // eslint-disable-next-line prefer-const
let [categories, loaders, licenses, donationPlatforms] = await Promise.all([ let [categories, loaders, licenses, donationPlatforms] = await Promise.all([
@@ -16,35 +16,35 @@ export async function tags(API_URL) {
await (await fetch(API_URL + 'tag/loader')).json(), await (await fetch(API_URL + 'tag/loader')).json(),
await (await fetch(API_URL + 'tag/license')).json(), await (await fetch(API_URL + 'tag/license')).json(),
await (await fetch(API_URL + 'tag/donation_platform')).json(), await (await fetch(API_URL + 'tag/donation_platform')).json(),
]); ])
progressBar.update(4); progressBar.update(4)
const tagIconReducer = (a, v) => ({ const tagIconReducer = (a, v) => ({
...a, ...a,
[v.name]: v.icon.replace('<svg', '<svg class="icon"'), [v.name]: v.icon.replace('<svg', '<svg class="icon"'),
}); })
// Create single object with icons // Create single object with icons
const tagIcons = { const tagIcons = {
...categories.reduce(tagIconReducer, {}), ...categories.reduce(tagIconReducer, {}),
...loaders.reduce(tagIconReducer, {}), ...loaders.reduce(tagIconReducer, {}),
}; }
progressBar.increment(); progressBar.increment()
// Delete icons from original arrays // Delete icons from original arrays
categories = categories.map(({ icon, ...rest }) => rest); categories = categories.map(({ icon, ...rest }) => rest)
loaders = loaders.map(({ icon, ...rest }) => rest); loaders = loaders.map(({ icon, ...rest }) => rest)
progressBar.increment(); progressBar.increment()
// Set project types // Set project types
const projectTypes = ['mod', 'modpack']; const projectTypes = ['mod', 'modpack']
// Write JSON file // Write JSON file
await fs.writeFile( await fs.writeFile(
'./generated/tags.json', './generated/tags.json',
JSON.stringify({ categories, loaders, projectTypes, licenses, donationPlatforms, tagIcons }) JSON.stringify({ categories, loaders, projectTypes, licenses, donationPlatforms, tagIcons })
); )
progressBar.increment(); progressBar.increment()
progressBar.stop(); progressBar.stop()
} }

View File

@@ -11,13 +11,13 @@ export function ago(
/** A Intl formater */ /** A Intl formater */
rft: Intl.RelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' }) rft: Intl.RelativeTimeFormat = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' })
): string { ): string {
const SECOND = 1000; const SECOND = 1000
const MINUTE = 60 * SECOND; const MINUTE = 60 * SECOND
const HOUR = 60 * MINUTE; const HOUR = 60 * MINUTE
const DAY = 24 * HOUR; const DAY = 24 * HOUR
const WEEK = 7 * DAY; const WEEK = 7 * DAY
const MONTH = 30 * DAY; const MONTH = 30 * DAY
const YEAR = 365 * DAY; const YEAR = 365 * DAY
const intervals = [ const intervals = [
{ ge: YEAR, divisor: YEAR, unit: 'year' }, { ge: YEAR, divisor: YEAR, unit: 'year' },
{ ge: MONTH, divisor: MONTH, unit: 'month' }, { ge: MONTH, divisor: MONTH, unit: 'month' },
@@ -27,17 +27,15 @@ export function ago(
{ ge: MINUTE, divisor: MINUTE, unit: 'minute' }, { ge: MINUTE, divisor: MINUTE, unit: 'minute' },
{ ge: 30 * SECOND, divisor: SECOND, unit: 'seconds' }, { ge: 30 * SECOND, divisor: SECOND, unit: 'seconds' },
{ ge: 0, divisor: 1, text: 'just now' }, { ge: 0, divisor: 1, text: 'just now' },
]; ]
const now = typeof nowDate === 'object' ? nowDate.getTime() : new Date(nowDate).getTime(); const now = typeof nowDate === 'object' ? nowDate.getTime() : new Date(nowDate).getTime()
const diff = now - (typeof date === 'object' ? date : new Date(date)).getTime(); const diff = now - (typeof date === 'object' ? date : new Date(date)).getTime()
const diffAbs = Math.abs(diff); const diffAbs = Math.abs(diff)
for (const interval of intervals) { for (const interval of intervals) {
if (diffAbs >= interval.ge) { if (diffAbs >= interval.ge) {
const x = Math.round(Math.abs(diff) / interval.divisor); const x = Math.round(Math.abs(diff) / interval.divisor)
const isFuture = diff < 0; const isFuture = diff < 0
return interval.unit return interval.unit ? rft.format(isFuture ? x : -x, interval.unit as Unit) : interval.text
? rft.format(isFuture ? x : -x, interval.unit as Unit)
: interval.text;
} }
} }
} }
@@ -56,4 +54,4 @@ type Unit =
| 'month' | 'month'
| 'months' | 'months'
| 'year' | 'year'
| 'years'; | 'years'

View File

@@ -1,3 +1,3 @@
export function classCombine(names) { export function classCombine(names) {
return names.filter((name) => name && !name.includes('undefined')).join(' '); return names.filter((name) => name && !name.includes('undefined')).join(' ')
} }

View File

@@ -1,4 +1,4 @@
export { ago } from './ago'; export { ago } from './ago'
export { Permissions } from './permissions'; export { Permissions } from './permissions'
export { formatVersions, getPrimary, downloadUrl } from './versions'; export { formatVersions, getPrimary, downloadUrl } from './versions'
export { markdown, markdownInline } from './parse'; export { markdown, markdownInline } from './parse'

View File

@@ -1,41 +1,41 @@
import { marked } from 'marked'; import { marked } from 'marked'
import hljs from 'highlight.js'; import hljs from 'highlight.js'
import insane from 'insane'; import insane from 'insane'
const renderer = new marked.Renderer(); const renderer = new marked.Renderer()
renderer.image = (href, text) => { renderer.image = (href, text) => {
if (/^https?:\/\/(www\.)?youtube\.com\/watch\?v=[a-zA-Z0-9_]{11}$/.test(href)) { if (/^https?:\/\/(www\.)?youtube\.com\/watch\?v=[a-zA-Z0-9_]{11}$/.test(href)) {
const id = href.substring(32, 43); const id = href.substring(32, 43)
return `<iframe src="https://www.youtube-nocookie.com/embed/${id}?&modestbranding=1&autoplay=0&rel=0" frameborder="0" allowfullscreen></iframe>`; return `<iframe src="https://www.youtube-nocookie.com/embed/${id}?&modestbranding=1&autoplay=0&rel=0" frameborder="0" allowfullscreen></iframe>`
} else { } else {
return `<img src="${href}" alt="${text}" />`; return `<img src="${href}" alt="${text}" />`
}
} }
};
renderer.link = (href, title, text) => { renderer.link = (href, title, text) => {
if (href === null) { if (href === null) {
return text; return text
} }
let out = '<a href="' + href + '" rel="external nofollow"'; let out = '<a href="' + href + '" rel="external nofollow"'
if (title) { if (title) {
out += ' title="' + title + '"'; out += ' title="' + title + '"'
}
out += '>' + text + '</a>'
return out
} }
out += '>' + text + '</a>';
return out;
};
marked.setOptions({ marked.setOptions({
renderer, renderer,
highlight: function (code, lang) { highlight: function (code, lang) {
const language = hljs.getLanguage(lang) ? lang : 'plaintext'; const language = hljs.getLanguage(lang) ? lang : 'plaintext'
return hljs.highlight(code, { language }).value; return hljs.highlight(code, { language }).value
}, },
langPrefix: 'hljs language-', langPrefix: 'hljs language-',
headerPrefix: '', headerPrefix: '',
gfm: true, gfm: true,
smartLists: true, smartLists: true,
}); })
function sanitize(html: string): string { function sanitize(html: string): string {
return insane(html, { return insane(html, {
@@ -106,19 +106,19 @@ function sanitize(html: string): string {
if (tag === 'iframe') { if (tag === 'iframe') {
return /^https?:\/\/(www\.)?(youtube|youtube-nocookie)\.com\/embed\/[a-zA-Z0-9_]{11}(\?)?(&modestbranding=1)?(&autoplay=0)?(&loop=1)?(&playlist=[a-zA-Z0-9_]{11})?(&rel=0)?$/.test( return /^https?:\/\/(www\.)?(youtube|youtube-nocookie)\.com\/embed\/[a-zA-Z0-9_]{11}(\?)?(&modestbranding=1)?(&autoplay=0)?(&loop=1)?(&playlist=[a-zA-Z0-9_]{11})?(&rel=0)?$/.test(
attrs.src || '' attrs.src || ''
); )
} else if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) { } else if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag)) {
return attrs.id !== 'svelte'; return attrs.id !== 'svelte'
} else if (tag === 'input') { } else if (tag === 'input') {
return attrs.type === 'checkbox' && attrs.disabled === ''; return attrs.type === 'checkbox' && attrs.disabled === ''
} else if (tag === 'code' || tag === 'span') { } else if (tag === 'code' || tag === 'span') {
return !attrs.class || attrs.class.replace(' ', '').startsWith('hljs'); return !attrs.class || attrs.class.replace(' ', '').startsWith('hljs')
} else { } else {
return true; return true
} }
}, },
transformText: null, transformText: null,
}); })
} }
export function markdownInline(markdown: string): string { export function markdownInline(markdown: string): string {
@@ -134,9 +134,9 @@ export function markdownInline(markdown: string): string {
transformText: null, transformText: null,
}, },
true true
); )
} }
export function markdown(markdown: string): string { export function markdown(markdown: string): string {
return sanitize(marked.parse(markdown)); return sanitize(marked.parse(markdown))
} }

View File

@@ -8,7 +8,7 @@ export class Permissions {
removeMember: false, removeMember: false,
editMember: false, editMember: false,
deleteProject: false, deleteProject: false,
}; }
get settingsPage(): boolean { get settingsPage(): boolean {
return ( return (
@@ -16,12 +16,12 @@ export class Permissions {
this.data.removeMember || this.data.removeMember ||
this.data.editMember || this.data.editMember ||
this.data.deleteProject this.data.deleteProject
); )
} }
constructor(from: number | 'ALL' | null) { constructor(from: number | 'ALL' | null) {
if (from === 'ALL' || from === 0b11111111 || from === null) { if (from === 'ALL' || from === 0b11111111 || from === null) {
Object.keys(this.data).forEach((v) => (this.data[v] = true)); Object.keys(this.data).forEach((v) => (this.data[v] = true))
} else if (typeof from === 'number') { } else if (typeof from === 'number') {
this.data = { this.data = {
uploadVersions: !!(from & (1 << 0)), uploadVersions: !!(from & (1 << 0)),
@@ -32,7 +32,7 @@ export class Permissions {
removeMember: !!(from & (1 << 5)), removeMember: !!(from & (1 << 5)),
editMember: !!(from & (1 << 6)), editMember: !!(from & (1 << 6)),
deleteProject: !!(from & (1 << 7)), deleteProject: !!(from & (1 << 7)),
}; }
} }
} }
} }

View File

@@ -1,6 +1,6 @@
let idCounter = 0; let idCounter = 0
export function uniqueId(prefix = ''): string { export function uniqueId(prefix = ''): string {
const id = ++idCounter; const id = ++idCounter
return prefix + id; return prefix + id
} }

View File

@@ -1,20 +1,20 @@
import gameVersions from '$generated/gameVersions.json'; import gameVersions from '$generated/gameVersions.json'
export function formatVersions(versionArray: string[]): string { export function formatVersions(versionArray: string[]): string {
const allVersions = gameVersions.slice().reverse(); const allVersions = gameVersions.slice().reverse()
const allReleases = allVersions.filter((x) => x.version_type === 'release'); const allReleases = allVersions.filter((x) => x.version_type === 'release')
const intervals = []; const intervals = []
let currentInterval = 0; let currentInterval = 0
for (let i = 0; i < versionArray.length; i++) { for (let i = 0; i < versionArray.length; i++) {
const index = allVersions.findIndex((x) => x.version === versionArray[i]); const index = allVersions.findIndex((x) => x.version === versionArray[i])
const releaseIndex = allReleases.findIndex((x) => x.version === versionArray[i]); const releaseIndex = allReleases.findIndex((x) => x.version === versionArray[i])
if (i === 0) { if (i === 0) {
intervals.push([[versionArray[i], index, releaseIndex]]); intervals.push([[versionArray[i], index, releaseIndex]])
} else { } else {
const intervalBase = intervals[currentInterval]; const intervalBase = intervals[currentInterval]
if ( if (
(index - intervalBase[intervalBase.length - 1][1] === 1 || (index - intervalBase[intervalBase.length - 1][1] === 1 ||
@@ -22,20 +22,20 @@ export function formatVersions(versionArray: string[]): string {
(allVersions[intervalBase[0][1]].version_type === 'release' || (allVersions[intervalBase[0][1]].version_type === 'release' ||
allVersions[index].version_type !== 'release') allVersions[index].version_type !== 'release')
) { ) {
intervalBase[1] = [versionArray[i], index, releaseIndex]; intervalBase[1] = [versionArray[i], index, releaseIndex]
} else { } else {
currentInterval += 1; currentInterval += 1
intervals[currentInterval] = [[versionArray[i], index, releaseIndex]]; intervals[currentInterval] = [[versionArray[i], index, releaseIndex]]
} }
} }
} }
const newIntervals = []; const newIntervals = []
for (let i = 0; i < intervals.length; i++) { for (let i = 0; i < intervals.length; i++) {
const interval = intervals[i]; const interval = intervals[i]
if (interval.length === 2 && interval[0][2] !== -1 && interval[1][2] === -1) { if (interval.length === 2 && interval[0][2] !== -1 && interval[1][2] === -1) {
let lastSnapshot = null; let lastSnapshot = null
for (let j = interval[1][1]; j > interval[0][1]; j--) { for (let j = interval[1][1]; j > interval[0][1]; j--) {
if (allVersions[j].version_type === 'release') { if (allVersions[j].version_type === 'release') {
newIntervals.push([ newIntervals.push([
@@ -45,42 +45,39 @@ export function formatVersions(versionArray: string[]): string {
j, j,
allReleases.findIndex((x) => x.version === allVersions[j].version), allReleases.findIndex((x) => x.version === allVersions[j].version),
], ],
]); ])
if (lastSnapshot !== null && lastSnapshot !== j + 1) { if (lastSnapshot !== null && lastSnapshot !== j + 1) {
newIntervals.push([ newIntervals.push([[allVersions[lastSnapshot].version, lastSnapshot, -1], interval[1]])
[allVersions[lastSnapshot].version, lastSnapshot, -1],
interval[1],
]);
} else { } else {
newIntervals.push([interval[1]]); newIntervals.push([interval[1]])
} }
break; break
} else { } else {
lastSnapshot = j; lastSnapshot = j
} }
} }
} else { } else {
newIntervals.push(interval); newIntervals.push(interval)
} }
} }
const output = []; const output = []
for (const interval of newIntervals) { for (const interval of newIntervals) {
if (interval.length === 2) { if (interval.length === 2) {
output.push(`${interval[0][0]}${interval[1][0]}`); output.push(`${interval[0][0]}${interval[1][0]}`)
} else { } else {
output.push(interval[0][0]); output.push(interval[0][0])
} }
} }
return output.join(', '); return output.join(', ')
} }
export const getPrimary = (files) => files.find((file) => file.primary) || files[0]; export const getPrimary = (files) => files.find((file) => file.primary) || files[0]
export function downloadUrl(file): string { export function downloadUrl(file): string {
return import.meta.env.VITE_API_URL + `version_file/${file?.hashes.sha1}/download`; return import.meta.env.VITE_API_URL + `version_file/${file?.hashes.sha1}/download`
} }

View File

@@ -9,7 +9,7 @@ To make use of the built-in icons, styles, and plugins in omorphia, you will nee
Add the following parts to your `svelte.config.js` file: Add the following parts to your `svelte.config.js` file:
```js ```js
import { preprocess, plugins } from 'omorphia/config/svelte.config'; import { preprocess, plugins } from 'omorphia/config/svelte.config'
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
@@ -20,9 +20,9 @@ const config = {
plugins: [...plugins], plugins: [...plugins],
}, },
}, },
}; }
export default config; export default config
``` ```
## PostCSS ## PostCSS
@@ -32,5 +32,5 @@ Create a `postcss.config.cjs` file in the root of your project.
Add the following line to that file: Add the following line to that file:
```js ```js
module.exports = require('omorphia/config/postcss.config.cjs'); module.exports = require('omorphia/config/postcss.config.cjs')
``` ```

View File

@@ -16,7 +16,7 @@ The generator plugin creates static files from API responses to increase perform
## Configuration ## Configuration
```js ```js
import Generator from 'omorphia/plugins/generator'; import Generator from 'omorphia/plugins/generator'
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
@@ -32,7 +32,7 @@ const config = {
], ],
}, },
}, },
}; }
export default config; export default config
``` ```

View File

@@ -59,14 +59,14 @@ The `markdownInline` parser is perfect for translations and short bios. It doesn
The `Permissions` class provides an easy way to manage user permissions. The `Permissions` class provides an easy way to manage user permissions.
```ts ```ts
import { Permissions } from 'omorphia/utils'; import { Permissions } from 'omorphia/utils'
const adminLevel = new Permissions('ALL'); const adminLevel = new Permissions('ALL')
const memberLevel = new Permissions(member.permissions); /* `member` from API */ const memberLevel = new Permissions(member.permissions) /* `member` from API */
const userLevel = new Permissions(0); const userLevel = new Permissions(0)
if (memberLevel.data.uploadVersions) { if (memberLevel.data.uploadVersions) {
console.log('Can upload versions!'); console.log('Can upload versions!')
} }
``` ```

View File

@@ -1,11 +1,11 @@
import { mdsvex } from 'mdsvex'; import { mdsvex } from 'mdsvex'
import mdsvexConfig from './mdsvex.config.js'; import mdsvexConfig from './mdsvex.config.js'
import adapter from '@sveltejs/adapter-static'; import adapter from '@sveltejs/adapter-static'
import examples from 'mdsvexamples/vite'; import examples from 'mdsvexamples/vite'
import sveld from './plugins/sveld.js'; import sveld from './plugins/sveld.js'
import path from 'path'; import path from 'path'
import { preprocess, plugins } from './src/package/config/svelte.config.js'; import { preprocess, plugins } from './src/package/config/svelte.config.js'
import Generator from './src/package/plugins/generator/index.js'; import Generator from './src/package/plugins/generator/index.js'
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
@@ -54,6 +54,6 @@ const config = {
lib: 'src/package', lib: 'src/package',
}, },
}, },
}; }
export default config; export default config