chore: format and update deps

This commit is contained in:
C4illin 2024-09-24 23:49:14 +02:00
parent e573997aa9
commit 4c747e8908
7 changed files with 96 additions and 83 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -5,9 +5,11 @@ services:
# dockerfile: Debian.Dockerfile # dockerfile: Debian.Dockerfile
volumes: volumes:
- ./data:/app/data - ./data:/app/data
environment: environment: # Defaults are listed below. All are optional.
- ACCOUNT_REGISTRATION=true - ACCOUNT_REGISTRATION=true # true or false, doesn't matter for the first account (e.g. keep this to false if you only want one account)
- JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 - JWT_SECRET=aLongAndSecretStringUsedToSignTheJSONWebToken1234 # will use randomUUID() by default
- ALLOW_UNAUTHENTICATED=true - HTTP_ALLOWED=true # setting this to true is unsafe, only set this to true locally
- ALLOW_UNAUTHENTICATED=true # allows anyone to use the service without logging in, only set this to true locally
- AUTO_DELETE_EVERY_N_HOURS=1 # checks every n hours for files older then n hours and deletes them, set to 0 to disable
ports: ports:
- 3000:3000 - 3000:3000

View file

@ -2,16 +2,16 @@ import { fixupPluginRules } from "@eslint/compat";
import tseslint from "typescript-eslint"; import tseslint from "typescript-eslint";
import eslint from "@eslint/js"; import eslint from "@eslint/js";
import deprecationPlugin from "eslint-plugin-deprecation"; import deprecationPlugin from "eslint-plugin-deprecation";
import eslintCommentsPlugin from "eslint-plugin-eslint-comments";
import importPlugin from "eslint-plugin-import"; import importPlugin from "eslint-plugin-import";
import simpleImportSortPlugin from "eslint-plugin-simple-import-sort"; import simpleImportSortPlugin from "eslint-plugin-simple-import-sort";
import tailwind from "eslint-plugin-tailwindcss";
import comments from "@eslint-community/eslint-plugin-eslint-comments/configs"
export default tseslint.config( export default tseslint.config(
{ {
plugins: { plugins: {
"@typescript-eslint": tseslint.plugin, "@typescript-eslint": tseslint.plugin,
deprecation: fixupPluginRules(deprecationPlugin), deprecation: fixupPluginRules(deprecationPlugin),
"eslint-comments": eslintCommentsPlugin,
import: fixupPluginRules(importPlugin), import: fixupPluginRules(importPlugin),
"simple-import-sort": simpleImportSortPlugin, "simple-import-sort": simpleImportSortPlugin,
}, },
@ -20,8 +20,10 @@ export default tseslint.config(
ignores: ["**/node_modules/**", "**/public/**"], ignores: ["**/node_modules/**", "**/public/**"],
}, },
eslint.configs.recommended, eslint.configs.recommended,
comments.recommended,
...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked, ...tseslint.configs.stylisticTypeChecked,
...tailwind.configs["flat/recommended"],
{ {
languageOptions: { languageOptions: {
parserOptions: { parserOptions: {
@ -32,5 +34,14 @@ export default tseslint.config(
project: ["./tsconfig.json"], project: ["./tsconfig.json"],
}, },
}, },
rules: {
"tailwindcss/no-custom-classname": [
"error",
{
"config": "./tailwind.config.js",
"whitelist": ['select_container', 'convert_to_popup', 'convert_to_group', 'target', 'convert_to_target']
}
],
}
}, },
); );

View file

@ -16,7 +16,7 @@
"@elysiajs/html": "1.0.2", "@elysiajs/html": "1.0.2",
"@elysiajs/jwt": "^1.1.1", "@elysiajs/jwt": "^1.1.1",
"@elysiajs/static": "1.0.3", "@elysiajs/static": "1.0.3",
"elysia": "^1.1.12" "elysia": "^1.1.16"
}, },
"module": "src/index.tsx", "module": "src/index.tsx",
"type": "module", "type": "module",
@ -25,37 +25,40 @@
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.9.2", "@biomejs/biome": "1.9.2",
"@eslint-community/eslint-plugin-eslint-comments": "^4.4.0",
"@eslint/compat": "^1.1.1", "@eslint/compat": "^1.1.1",
"@eslint/js": "^9.9.1", "@eslint/js": "^9.11.1",
"@ianvs/prettier-plugin-sort-imports": "^4.3.1", "@ianvs/prettier-plugin-sort-imports": "^4.3.1",
"@kitajs/ts-html-plugin": "^4.0.2", "@kitajs/ts-html-plugin": "^4.1.0",
"@picocss/pico": "^2.0.6", "@picocss/pico": "^2.0.6",
"@total-typescript/ts-reset": "^0.6.1", "@total-typescript/ts-reset": "^0.6.1",
"@types/bun": "^1.1.8", "@types/bun": "^1.1.10",
"@types/eslint": "^9.6.1", "@types/eslint": "^9.6.1",
"@types/node": "^22.5.4", "@types/eslint-plugin-tailwindcss": "^3.17.0",
"@typescript-eslint/eslint-plugin": "^8.4.0", "@types/eslint__js": "^8.42.3",
"@typescript-eslint/parser": "^8.4.0", "@types/node": "^22.6.1",
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"cssnano": "^7.0.6", "cssnano": "^7.0.6",
"eslint": "^9.9.1", "eslint": "^9.11.1",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-deprecation": "^3.0.0", "eslint-plugin-deprecation": "^3.0.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.30.0", "eslint-plugin-import": "^2.30.0",
"eslint-plugin-isaacscript": "^4.0.0", "eslint-plugin-isaacscript": "^4.0.0",
"eslint-plugin-prettier": "^5.2.1", "eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-simple-import-sort": "^12.1.1",
"knip": "^5.29.2", "eslint-plugin-tailwindcss": "^3.17.4",
"npm-run-all2": "^6.2.2", "knip": "^5.30.5",
"npm-run-all2": "^6.2.3",
"postcss": "^8.4.47", "postcss": "^8.4.47",
"postcss-cli": "^11.0.0", "postcss-cli": "^11.0.0",
"postcss-lightningcss": "^1.0.1", "postcss-lightningcss": "^1.0.1",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"tailwind-scrollbar": "^3.1.0", "tailwind-scrollbar": "^3.1.0",
"tailwindcss": "^3.4.12", "tailwindcss": "^3.4.13",
"typescript": "^5.5.4", "typescript": "^5.6.2",
"typescript-eslint": "^8.4.0" "typescript-eslint": "^8.7.0"
}, },
"trustedDependencies": [ "trustedDependencies": [
"@biomejs/biome" "@biomejs/biome"

View file

@ -34,20 +34,15 @@ import { normalizeFiletype } from "../helpers/normalizeFiletype";
// This should probably be reconstructed so that the functions are not imported instead the functions hook into this to make the converters more modular // This should probably be reconstructed so that the functions are not imported instead the functions hook into this to make the converters more modular
const properties: { const properties: Record<string, {
[key: string]: {
properties: { properties: {
from: { [key: string]: string[] }; from: Record<string, string[]>;
to: { [key: string]: string[] }; to: Record<string, string[]>;
options?: { options?: Record<string, Record<string, {
[key: string]: {
[key: string]: {
description: string; description: string;
type: string; type: string;
default: number; default: number;
}; }>>;
};
};
}; };
converter: ( converter: (
filePath: string, filePath: string,
@ -58,8 +53,7 @@ const properties: {
options?: any, options?: any,
// biome-ignore lint/suspicious/noExplicitAny: <explanation> // biome-ignore lint/suspicious/noExplicitAny: <explanation>
) => any; ) => any;
}; }> = {
} = {
libjxl: { libjxl: {
properties: propertiesLibjxl, properties: propertiesLibjxl,
converter: convertLibjxl, converter: convertLibjxl,
@ -159,7 +153,7 @@ export async function mainConverter(
} }
} }
const possibleTargets: { [key: string]: { [key: string]: string[] } } = {}; const possibleTargets: Record<string, Record<string, string[]>> = {};
for (const converterName in properties) { for (const converterName in properties) {
const converterProperties = properties[converterName]?.properties; const converterProperties = properties[converterName]?.properties;
@ -186,7 +180,7 @@ for (const converterName in properties) {
export const getPossibleTargets = ( export const getPossibleTargets = (
from: string, from: string,
): { [key: string]: string[] } => { ): Record<string, string[]> => {
const fromClean = normalizeFiletype(from); const fromClean = normalizeFiletype(from);
return possibleTargets[fromClean] || {}; return possibleTargets[fromClean] || {};
@ -214,7 +208,7 @@ const getPossibleInputs = () => {
return possibleInputs; return possibleInputs;
}; };
const allTargets: { [key: string]: string[] } = {}; const allTargets: Record<string, string[]> = {};
for (const converterName in properties) { for (const converterName in properties) {
const converterProperties = properties[converterName]?.properties; const converterProperties = properties[converterName]?.properties;
@ -236,7 +230,7 @@ export const getAllTargets = () => {
return allTargets; return allTargets;
}; };
const allInputs: { [key: string]: string[] } = {}; const allInputs: Record<string, string[]> = {};
for (const converterName in properties) { for (const converterName in properties) {
const converterProperties = properties[converterName]?.properties; const converterProperties = properties[converterName]?.properties;

View file

@ -138,8 +138,8 @@ const app = new Elysia({
return ( return (
<BaseHtml title="ConvertX | Setup"> <BaseHtml title="ConvertX | Setup">
<main class="w-full mx-auto max-w-4xl px-4"> <main class="mx-auto w-full max-w-4xl px-4">
<h1 class="text-3xl my-8">Welcome to ConvertX!</h1> <h1 class="my-8 text-3xl">Welcome to ConvertX!</h1>
<article class="article p-0"> <article class="article p-0">
<header class="w-full bg-gray-800 p-4">Create your account</header> <header class="w-full bg-gray-800 p-4">Create your account</header>
<form method="post" action="/register" class="p-4"> <form method="post" action="/register" class="p-4">
@ -172,7 +172,7 @@ const app = new Elysia({
<footer class="p-4"> <footer class="p-4">
Report any issues on{" "} Report any issues on{" "}
<a <a
class="underline text-lime-500 hover:text-lime-400" class="text-lime-500 underline hover:text-lime-400"
href="https://github.com/C4illin/ConvertX"> href="https://github.com/C4illin/ConvertX">
GitHub GitHub
</a> </a>
@ -343,7 +343,7 @@ const app = new Elysia({
</fieldset> </fieldset>
<div role="group"> <div role="group">
{ACCOUNT_REGISTRATION ? ( {ACCOUNT_REGISTRATION ? (
<a href="/register" role="button" class="secondary"> <a href="/register" role="button" class="btn-primary w-full">
Register an account Register an account
</a> </a>
) : null} ) : null}
@ -456,7 +456,12 @@ const app = new Elysia({
} }
} }
} else if (ALLOW_UNAUTHENTICATED) { } else if (ALLOW_UNAUTHENTICATED) {
const newUserId = String(randomInt(2 ** 24, Math.min(2 ** 48 + 2 ** 24 - 1, Number.MAX_SAFE_INTEGER))); const newUserId = String(
randomInt(
2 ** 24,
Math.min(2 ** 48 + 2 ** 24 - 1, Number.MAX_SAFE_INTEGER),
),
);
const accessToken = await jwt.sign({ const accessToken = await jwt.sign({
id: newUserId, id: newUserId,
}); });
@ -515,15 +520,15 @@ const app = new Elysia({
<main class="w-full px-4"> <main class="w-full px-4">
<article class="article"> <article class="article">
<h1 class="mb-4 text-xl">Convert</h1> <h1 class="mb-4 text-xl">Convert</h1>
<div class="max-h-[50vh] overflow-y-auto mb-4 scrollbar-thin"> <div class="mb-4 max-h-[50vh] overflow-y-auto scrollbar-thin">
<table <table
id="file-list" id="file-list"
class="table-auto w-full bg-gray-900 [&_td]:p-4 rounded [&_tr]:border-b [&_tr]:border-gray-800 [&_tr]:rounded" class="w-full table-auto rounded bg-gray-900 [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-gray-800"
/> />
</div> </div>
<div <div
id="dropzone" id="dropzone"
class="relative flex h-48 w-full items-center justify-center rounded border border-gray-700 border-dashed transition-all hover:border-gray-600 [&.dragover]:border-4 [&.dragover]:border-gray-500"> class="relative flex h-48 w-full items-center justify-center rounded border border-dashed border-gray-700 transition-all hover:border-gray-600 [&.dragover]:border-4 [&.dragover]:border-gray-500">
<span> <span>
<b>Choose a file</b> or drag it here <b>Choose a file</b> or drag it here
</span> </span>
@ -538,7 +543,7 @@ const app = new Elysia({
<form <form
method="post" method="post"
action="/convert" action="/convert"
class="relative w-full mx-auto max-w-4xl mb-[35vh]"> class="relative mx-auto mb-[35vh] w-full max-w-4xl">
<input type="hidden" name="file_names" id="file_names" /> <input type="hidden" name="file_names" id="file_names" />
<article class="article w-full"> <article class="article w-full">
<input <input
@ -549,21 +554,21 @@ const app = new Elysia({
class="w-full rounded bg-gray-800 p-4" class="w-full rounded bg-gray-800 p-4"
/> />
<div class="select_container relative"> <div class="select_container relative">
<article class="convert_to_popup flex-col absolute z-[2] max-h-[50vh] h-[30vh] w-full overflow-y-auto m-0 overflow-x-hidden hidden bg-gray-800 sm:h-[30vh] rounded"> <article class="convert_to_popup absolute z-[2] m-0 hidden h-[30vh] max-h-[50vh] w-full flex-col overflow-y-auto overflow-x-hidden rounded bg-gray-800 sm:h-[30vh]">
{Object.entries(getAllTargets()).map( {Object.entries(getAllTargets()).map(
([converter, targets]) => ( ([converter, targets]) => (
<article <article
class="convert_to_group border-gray-700 border-b p-4 w-full" class="convert_to_group w-full border-b border-gray-700 p-4"
data-converter={converter}> data-converter={converter}>
<header class="text-xl font-bold w-full mb-2" safe> <header class="mb-2 w-full text-xl font-bold" safe>
{converter} {converter}
</header> </header>
<ul class="convert_to_target flex flex-row gap-1 flex-wrap"> <ul class="convert_to_target flex flex-row flex-wrap gap-1">
{targets.map((target) => ( {targets.map((target) => (
<button <button
// https://stackoverflow.com/questions/121499/when-a-blur-event-occurs-how-can-i-find-out-which-element-focus-went-to#comment82388679_33325953 // https://stackoverflow.com/questions/121499/when-a-blur-event-occurs-how-can-i-find-out-which-element-focus-went-to#comment82388679_33325953
tabindex={0} tabindex={0}
class="target p-1 text-base bg-gray-700 rounded hover:bg-gray-600" class="target rounded bg-gray-700 p-1 text-base hover:bg-gray-600"
data-value={`${target},${converter}`} data-value={`${target},${converter}`}
data-target={target} data-target={target}
data-converter={converter} data-converter={converter}
@ -614,21 +619,21 @@ const app = new Elysia({
({ body }) => { ({ body }) => {
return ( return (
<> <>
<article class="convert_to_popup flex-col absolute z-[2] max-h-[50vh] h-[50vh] w-full overflow-y-auto m-0 overflow-x-hidden hidden bg-gray-800 sm:h-[30vh] rounded"> <article class="convert_to_popup absolute z-[2] m-0 hidden h-[50vh] max-h-[50vh] w-full flex-col overflow-y-auto overflow-x-hidden rounded bg-gray-800 sm:h-[30vh]">
{Object.entries(getPossibleTargets(body.fileType)).map( {Object.entries(getPossibleTargets(body.fileType)).map(
([converter, targets]) => ( ([converter, targets]) => (
<article <article
class="convert_to_group border-gray-700 border-b p-4 w-full" class="convert_to_group w-full border-b border-gray-700 p-4"
data-converter={converter}> data-converter={converter}>
<header class="text-xl font-bold w-full mb-2" safe> <header class="mb-2 w-full text-xl font-bold" safe>
{converter} {converter}
</header> </header>
<ul class="convert_to_target flex flex-row gap-1 flex-wrap"> <ul class="convert_to_target flex flex-row flex-wrap gap-1">
{targets.map((target) => ( {targets.map((target) => (
<button <button
// https://stackoverflow.com/questions/121499/when-a-blur-event-occurs-how-can-i-find-out-which-element-focus-went-to#comment82388679_33325953 // https://stackoverflow.com/questions/121499/when-a-blur-event-occurs-how-can-i-find-out-which-element-focus-went-to#comment82388679_33325953
tabindex={0} tabindex={0}
class="target p-1 text-base bg-gray-700 rounded hover:bg-gray-600" class="target rounded bg-gray-700 p-1 text-base hover:bg-gray-600"
data-value={`${target},${converter}`} data-value={`${target},${converter}`}
data-target={target} data-target={target}
data-converter={converter} data-converter={converter}
@ -875,8 +880,8 @@ const app = new Elysia({
<Header loggedIn /> <Header loggedIn />
<main class="w-full px-4"> <main class="w-full px-4">
<article class="article"> <article class="article">
<h1 class="text-xl mb-4">Results</h1> <h1 class="mb-4 text-xl">Results</h1>
<table class="table-auto w-full bg-gray-900 [&_td]:p-4 rounded [&_tr]:border-b [&_tr]:border-gray-800 [&_tr]:rounded text-left"> <table class="w-full table-auto rounded bg-gray-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-gray-800">
<thead> <thead>
<tr> <tr>
<th class="px-4 py-2">Time</th> <th class="px-4 py-2">Time</th>
@ -895,7 +900,7 @@ const app = new Elysia({
<td safe>{job.status}</td> <td safe>{job.status}</td>
<td> <td>
<a <a
class="underline text-lime-500 hover:text-lime-400" class="text-lime-500 underline hover:text-lime-400"
href={`/results/${job.id}`}> href={`/results/${job.id}`}>
View View
</a> </a>
@ -952,12 +957,12 @@ const app = new Elysia({
<Header loggedIn /> <Header loggedIn />
<main class="w-full px-4"> <main class="w-full px-4">
<article class="article"> <article class="article">
<div class="flex items-center justify-between mb-4"> <div class="mb-4 flex items-center justify-between">
<h1 class="text-xl">Results</h1> <h1 class="text-xl">Results</h1>
<div> <div>
<button <button
type="button" type="button"
class="w-40 float-right btn-primary" class="btn-primary float-right w-40"
onclick="downloadAll()" onclick="downloadAll()"
{...(files.length !== job.num_files {...(files.length !== job.num_files
? { disabled: true, "aria-busy": "true" } ? { disabled: true, "aria-busy": "true" }
@ -971,9 +976,9 @@ const app = new Elysia({
<progress <progress
max={job.num_files} max={job.num_files}
value={files.length} value={files.length}
class="w-full rounded-full mb-4 h-2 border-0 inline-block appearance-none overflow-hidden bg-none bg-gray-700 text-lime-500 accent-lime-500 [&::-moz-progress-bar]:bg-gray-700 [&::-webkit-progress-value]:[ background:none] [&::-webkit-progress-value]:rounded-full [&[value]::-webkit-progress-value]:bg-lime-500 [&[value]::-webkit-progress-value]:transition-[inline-size]" class="mb-4 inline-block h-2 w-full appearance-none overflow-hidden rounded-full border-0 bg-gray-700 bg-none text-lime-500 accent-lime-500 [&::-moz-progress-bar]:bg-gray-700 [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:[background:none] [&[value]::-webkit-progress-value]:bg-lime-500 [&[value]::-webkit-progress-value]:transition-[inline-size]"
/> />
<table class="table-auto w-full bg-gray-900 [&_td]:p-4 rounded [&_tr]:border-b [&_tr]:border-gray-800 [&_tr]:rounded text-left"> <table class="w-full table-auto rounded bg-gray-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-gray-800">
<thead> <thead>
<tr> <tr>
<th class="px-4 py-2">Converted File Name</th> <th class="px-4 py-2">Converted File Name</th>
@ -989,14 +994,14 @@ const app = new Elysia({
<td safe>{file.status}</td> <td safe>{file.status}</td>
<td> <td>
<a <a
class="underline text-lime-500 hover:text-lime-400" class="text-lime-500 underline hover:text-lime-400"
href={`/download/${outputPath}${file.output_file_name}`}> href={`/download/${outputPath}${file.output_file_name}`}>
View View
</a> </a>
</td> </td>
<td> <td>
<a <a
class="underline text-lime-500 hover:text-lime-400" class="text-lime-500 underline hover:text-lime-400"
href={`/download/${outputPath}${file.output_file_name}`} href={`/download/${outputPath}${file.output_file_name}`}
download={file.output_file_name}> download={file.output_file_name}>
Download Download
@ -1052,12 +1057,12 @@ const app = new Elysia({
return ( return (
<article class="article"> <article class="article">
<div class="flex items-center justify-between mb-4"> <div class="mb-4 flex items-center justify-between">
<h1 class="text-xl">Results</h1> <h1 class="text-xl">Results</h1>
<div> <div>
<button <button
type="button" type="button"
class="w-40 float-right btn-primary" class="btn-primary float-right w-40"
onclick="downloadAll()" onclick="downloadAll()"
{...(files.length !== job.num_files {...(files.length !== job.num_files
? { disabled: true, "aria-busy": "true" } ? { disabled: true, "aria-busy": "true" }
@ -1071,9 +1076,9 @@ const app = new Elysia({
<progress <progress
max={job.num_files} max={job.num_files}
value={files.length} value={files.length}
class="w-full rounded-full mb-4 h-2 border-0 inline-block appearance-none overflow-hidden bg-none bg-gray-700 text-lime-500 accent-lime-500 [&::-moz-progress-bar]:bg-gray-700 [&::-webkit-progress-value]:[ background:none] [&::-webkit-progress-value]:rounded-full [&[value]::-webkit-progress-value]:bg-lime-500 [&[value]::-webkit-progress-value]:transition-[inline-size]" class="mb-4 inline-block h-2 w-full appearance-none overflow-hidden rounded-full border-0 bg-gray-700 bg-none text-lime-500 accent-lime-500 [&::-moz-progress-bar]:bg-gray-700 [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:[background:none] [&[value]::-webkit-progress-value]:bg-lime-500 [&[value]::-webkit-progress-value]:transition-[inline-size]"
/> />
<table class="table-auto w-full bg-gray-900 [&_td]:p-4 rounded [&_tr]:border-b [&_tr]:border-gray-800 [&_tr]:rounded text-left"> <table class="w-full table-auto rounded bg-gray-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-gray-800">
<thead> <thead>
<tr> <tr>
<th class="px-4 py-2">Converted File Name</th> <th class="px-4 py-2">Converted File Name</th>
@ -1089,14 +1094,14 @@ const app = new Elysia({
<td safe>{file.status}</td> <td safe>{file.status}</td>
<td> <td>
<a <a
class="underline text-lime-500 hover:text-lime-400" class="text-lime-500 underline hover:text-lime-400"
href={`/download/${outputPath}${file.output_file_name}`}> href={`/download/${outputPath}${file.output_file_name}`}>
View View
</a> </a>
</td> </td>
<td> <td>
<a <a
class="underline text-lime-500 hover:text-lime-400" class="text-lime-500 underline hover:text-lime-400"
href={`/download/${outputPath}${file.output_file_name}`} href={`/download/${outputPath}${file.output_file_name}`}
download={file.output_file_name}> download={file.output_file_name}>
Download Download
@ -1155,7 +1160,7 @@ const app = new Elysia({
<main class="w-full px-4"> <main class="w-full px-4">
<article class="article"> <article class="article">
<h1 class="mb-4 text-xl">Converters</h1> <h1 class="mb-4 text-xl">Converters</h1>
<table class="table-auto w-full bg-gray-900 [&_td]:p-4 rounded [&_tr]:border-b [&_tr]:border-gray-800 [&_tr]:rounded text-left [&_ul]:list-inside [&_ul]:list-disc"> <table class="w-full table-auto rounded bg-gray-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-gray-800 [&_ul]:list-inside [&_ul]:list-disc">
<thead> <thead>
<tr> <tr>
<th class="mx-4 my-2">Converter</th> <th class="mx-4 my-2">Converter</th>
@ -1230,19 +1235,16 @@ const app = new Elysia({
// log.error(` ${request.method} ${request.url}`, code, error); // log.error(` ${request.method} ${request.url}`, code, error);
console.error(error); console.error(error);
}); });
if (process.env.NODE_ENV !== "production") { if (process.env.NODE_ENV !== "production") {
await import("./helpers/tailwind").then( await import("./helpers/tailwind").then(async ({ generateTailwind }) => {
async ({ generateTailwind }) => { const result = await generateTailwind();
const result = await generateTailwind()
app.get("/style.css", ({ set }) => { app.get("/style.css", ({ set }) => {
set.headers["content-type"] = "text/css"; set.headers["content-type"] = "text/css";
return result; return result;
}); });
}, });
);
} }
app.listen(3000); app.listen(3000);

View file

@ -1,9 +1,10 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
import scrollbar from 'tailwind-scrollbar';
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
module.exports = { module.exports = {
content: ["./src/**/*.{html,js,tsx}"], content: ["./src/**/*.{html,js,tsx,jsx,cjs,mjs}"],
theme: { theme: {
extend: {}, extend: {},
}, },
plugins: [import('tailwind-scrollbar')], plugins: [scrollbar()],
} }