mirror of
https://github.com/C4illin/ConvertX.git
synced 2025-11-05 14:35:27 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
663b1d4171 | ||
|
|
c3067ca12d | ||
|
|
4561ca3760 | ||
|
|
698cce58ce | ||
|
|
339b79f786 | ||
|
|
4f98f778f0 | ||
|
|
8479b33a47 | ||
|
|
78844d7bd5 | ||
|
|
64e4a271e1 | ||
|
|
5fb8c3575b | ||
|
|
a6b8bcecae | ||
|
|
bc9c820820 | ||
|
|
ee9207a7f4 | ||
|
|
a34e215202 | ||
|
|
b4e53dbb8e | ||
|
|
b5e8d82bfa | ||
|
|
5d9000bb33 | ||
|
|
ccb065ef0f |
@@ -1,7 +0,0 @@
|
|||||||
version = 1
|
|
||||||
|
|
||||||
[[analyzers]]
|
|
||||||
name = "javascript"
|
|
||||||
|
|
||||||
[analyzers.meta]
|
|
||||||
environment = ["nodejs"]
|
|
||||||
@@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.8.1](https://github.com/C4illin/ConvertX/compare/v0.8.0...v0.8.1) (2024-10-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* disable convert button when input is empty ([78844d7](https://github.com/C4illin/ConvertX/commit/78844d7bd55990789ed07c81e49043e688cbe656)), closes [#151](https://github.com/C4illin/ConvertX/issues/151)
|
||||||
|
* resize to fit for ico ([b4e53db](https://github.com/C4illin/ConvertX/commit/b4e53dbb8e70b3a95b44e5b756759d16117a87e1)), closes [#157](https://github.com/C4illin/ConvertX/issues/157)
|
||||||
|
* treat jfif as jpeg ([339b79f](https://github.com/C4illin/ConvertX/commit/339b79f786131deb93f0d5683e03178fdcab1ef5)), closes [#163](https://github.com/C4illin/ConvertX/issues/163)
|
||||||
|
|
||||||
## [0.8.0](https://github.com/C4illin/ConvertX/compare/v0.7.0...v0.8.0) (2024-09-30)
|
## [0.8.0](https://github.com/C4illin/ConvertX/compare/v0.7.0...v0.8.0) (2024-09-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
import comments from "@eslint-community/eslint-plugin-eslint-comments/configs";
|
|
||||||
import { fixupPluginRules } from "@eslint/compat";
|
import { fixupPluginRules } from "@eslint/compat";
|
||||||
import js from "@eslint/js";
|
import eslint from "@eslint/js";
|
||||||
import deprecationPlugin from "eslint-plugin-deprecation";
|
import deprecationPlugin from "eslint-plugin-deprecation";
|
||||||
import importPlugin from "eslint-plugin-import";
|
import eslintPluginReadableTailwind from "eslint-plugin-readable-tailwind";
|
||||||
import simpleImportSortPlugin from "eslint-plugin-simple-import-sort";
|
import simpleImportSortPlugin from "eslint-plugin-simple-import-sort";
|
||||||
import tailwind from "eslint-plugin-tailwindcss";
|
import tailwind from "eslint-plugin-tailwindcss";
|
||||||
import globals from "globals";
|
import globals from "globals";
|
||||||
import tseslint from "typescript-eslint";
|
import tseslint from "typescript-eslint";
|
||||||
|
|
||||||
export default tseslint.config(
|
export default tseslint.config(
|
||||||
js.configs.recommended,
|
eslint.configs.recommended,
|
||||||
importPlugin.flatConfigs.recommended,
|
|
||||||
comments.recommended,
|
|
||||||
...tseslint.configs.recommended,
|
...tseslint.configs.recommended,
|
||||||
...tailwind.configs["flat/recommended"],
|
...tailwind.configs["flat/recommended"],
|
||||||
{
|
{
|
||||||
plugins: {
|
plugins: {
|
||||||
"@typescript-eslint": tseslint.plugin,
|
|
||||||
deprecation: fixupPluginRules(deprecationPlugin),
|
deprecation: fixupPluginRules(deprecationPlugin),
|
||||||
import: fixupPluginRules(importPlugin),
|
|
||||||
"simple-import-sort": simpleImportSortPlugin,
|
"simple-import-sort": simpleImportSortPlugin,
|
||||||
|
"readable-tailwind": eslintPluginReadableTailwind,
|
||||||
},
|
},
|
||||||
ignores: ["**/node_modules/**", "**/public/**"],
|
ignores: ["**/node_modules/**"],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
projectService: true,
|
projectService: true,
|
||||||
@@ -32,14 +28,23 @@ export default tseslint.config(
|
|||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
...globals.node,
|
...globals.node,
|
||||||
|
...globals.browser,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
files: ["**/*.{js,mjs,cjs}"],
|
files: ["**/*.{js,mjs,cjs,tsx,ts}"],
|
||||||
rules: {
|
rules: {
|
||||||
"tailwindcss/no-custom-classname": [
|
...eslintPluginReadableTailwind.configs.warning.rules,
|
||||||
"error",
|
"tailwindcss/classnames-order": "off",
|
||||||
|
"readable-tailwind/multiline": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
group: "newLine",
|
||||||
|
printWidth: 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tailwindcss/no-custom-classname": [
|
||||||
|
"warn",
|
||||||
{
|
{
|
||||||
config: "./tailwind.config.js",
|
|
||||||
whitelist: [
|
whitelist: [
|
||||||
"select_container",
|
"select_container",
|
||||||
"convert_to_popup",
|
"convert_to_popup",
|
||||||
@@ -49,7 +54,6 @@ export default tseslint.config(
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"import/no-named-as-default": "off",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
22
package.json
22
package.json
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "convertx-frontend",
|
"name": "convertx-frontend",
|
||||||
"version": "0.8.0",
|
"version": "0.8.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "bun run --watch src/index.tsx",
|
"dev": "bun run --watch src/index.tsx",
|
||||||
"hot": "bun run --hot src/index.tsx",
|
"hot": "bun run --hot src/index.tsx",
|
||||||
"format": "biome format --write ./src",
|
"format": "eslint --fix .",
|
||||||
"build": "postcss ./src/main.css -o ./src/public/generated.css",
|
"build": "postcss ./src/main.css -o ./src/public/generated.css",
|
||||||
"lint": "run-p 'lint:*'",
|
"lint": "run-p 'lint:*'",
|
||||||
"lint:tsc": "tsc --noEmit",
|
"lint:tsc": "tsc --noEmit",
|
||||||
"lint:knip": "knip",
|
"lint:knip": "knip",
|
||||||
"lint:biome": "biome lint --error-on-warnings ./src"
|
"lint:eslint": "eslint ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elysiajs/cookie": "^0.8.0",
|
"@elysiajs/cookie": "^0.8.0",
|
||||||
@@ -24,13 +24,10 @@
|
|||||||
"start": "bun run src/index.tsx"
|
"start": "bun run src/index.tsx"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@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.11.1",
|
"@eslint/js": "^9.12.0",
|
||||||
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
|
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",
|
||||||
"@kitajs/ts-html-plugin": "^4.1.0",
|
"@kitajs/ts-html-plugin": "^4.1.0",
|
||||||
"@picocss/pico": "^2.0.6",
|
|
||||||
"@total-typescript/ts-reset": "^0.6.1",
|
"@total-typescript/ts-reset": "^0.6.1",
|
||||||
"@types/bun": "^1.1.10",
|
"@types/bun": "^1.1.10",
|
||||||
"@types/eslint": "^9.6.1",
|
"@types/eslint": "^9.6.1",
|
||||||
@@ -41,12 +38,12 @@
|
|||||||
"@typescript-eslint/parser": "^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.11.1",
|
"eslint": "^9.12.0",
|
||||||
"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-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-readable-tailwind": "^1.8.1",
|
||||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||||
"eslint-plugin-tailwindcss": "^3.17.4",
|
"eslint-plugin-tailwindcss": "^3.17.4",
|
||||||
"globals": "^15.9.0",
|
"globals": "^15.9.0",
|
||||||
@@ -59,9 +56,6 @@
|
|||||||
"tailwind-scrollbar": "^3.1.0",
|
"tailwind-scrollbar": "^3.1.0",
|
||||||
"tailwindcss": "^3.4.13",
|
"tailwindcss": "^3.4.13",
|
||||||
"typescript": "^5.6.2",
|
"typescript": "^5.6.2",
|
||||||
"typescript-eslint": "^8.7.0"
|
"typescript-eslint": "^8.8.0"
|
||||||
},
|
}
|
||||||
"trustedDependencies": [
|
|
||||||
"@biomejs/biome"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
// eslint-disable-next-line no-undef
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {},
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
|
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": [
|
||||||
"config:recommended"
|
"config:recommended",
|
||||||
|
":disableDependencyDashboard"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,20 @@ export const Header = ({
|
|||||||
<ul class="flex gap-4">
|
<ul class="flex gap-4">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
class="text-accent-600 transition-all hover:text-accent-500 hover:underline"
|
class={`
|
||||||
|
text-accent-600 transition-all
|
||||||
|
hover:text-accent-500 hover:underline
|
||||||
|
`}
|
||||||
href="/history">
|
href="/history">
|
||||||
History
|
History
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
class="text-accent-600 transition-all hover:text-accent-500 hover:underline"
|
class={`
|
||||||
|
text-accent-600 transition-all
|
||||||
|
hover:text-accent-500 hover:underline
|
||||||
|
`}
|
||||||
href="/logoff">
|
href="/logoff">
|
||||||
Logout
|
Logout
|
||||||
</a>
|
</a>
|
||||||
@@ -27,7 +33,10 @@ export const Header = ({
|
|||||||
<ul class="flex gap-4">
|
<ul class="flex gap-4">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
class="text-accent-600 transition-all hover:text-accent-500 hover:underline"
|
class={`
|
||||||
|
text-accent-600 transition-all
|
||||||
|
hover:text-accent-500 hover:underline
|
||||||
|
`}
|
||||||
href="/login">
|
href="/login">
|
||||||
Login
|
Login
|
||||||
</a>
|
</a>
|
||||||
@@ -35,7 +44,10 @@ export const Header = ({
|
|||||||
{accountRegistration ? (
|
{accountRegistration ? (
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
class="text-accent-600 transition-all hover:text-accent-500 hover:underline"
|
class={`
|
||||||
|
text-accent-600 transition-all
|
||||||
|
hover:text-accent-500 hover:underline
|
||||||
|
`}
|
||||||
href="/register">
|
href="/register">
|
||||||
Register
|
Register
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ export async function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
// let command = "ffmpeg";
|
// let command = "ffmpeg";
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ export async function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve("Done");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { exec } from "node:child_process";
|
import { exec } from "node:child_process";
|
||||||
|
|
||||||
|
|
||||||
// This could be done dynamically by running `ffmpeg -formats` and parsing the output
|
// This could be done dynamically by running `ffmpeg -formats` and parsing the output
|
||||||
export const properties = {
|
export const properties = {
|
||||||
from: {
|
from: {
|
||||||
@@ -689,10 +688,19 @@ export async function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const command = `ffmpeg -i "${filePath}" "${targetPath}"`;
|
let extra = "";
|
||||||
|
let message = "Done";
|
||||||
|
|
||||||
|
if (convertTo === "ico") {
|
||||||
|
// make sure image is 256x256 or smaller
|
||||||
|
extra = `-filter:v "scale='min(256,iw)':min'(256,ih)':force_original_aspect_ratio=decrease"`;
|
||||||
|
message = "Done: resized to 256x256";
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = `ffmpeg -i "${filePath}" ${extra} "${targetPath}"`;
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(command, (error, stdout, stderr) => {
|
exec(command, (error, stdout, stderr) => {
|
||||||
@@ -708,7 +716,7 @@ export async function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve(message);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -313,8 +313,8 @@ export function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(
|
exec(
|
||||||
@@ -332,7 +332,7 @@ export function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve("Done");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ export function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
let tool = "";
|
let tool = "";
|
||||||
if (fileType === "jxl") {
|
if (fileType === "jxl") {
|
||||||
@@ -65,7 +65,7 @@ export function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve("Done");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,44 @@
|
|||||||
import {
|
|
||||||
convert as convertImage,
|
|
||||||
properties as propertiesImage
|
|
||||||
} from "./vips";
|
|
||||||
|
|
||||||
import {
|
|
||||||
convert as convertPandoc,
|
|
||||||
properties as propertiesPandoc,
|
|
||||||
} from "./pandoc";
|
|
||||||
|
|
||||||
import {
|
|
||||||
convert as convertFFmpeg,
|
|
||||||
properties as propertiesFFmpeg,
|
|
||||||
} from "./ffmpeg";
|
|
||||||
|
|
||||||
import {
|
|
||||||
convert as convertGraphicsmagick,
|
|
||||||
properties as propertiesGraphicsmagick,
|
|
||||||
} from "./graphicsmagick";
|
|
||||||
|
|
||||||
import {
|
|
||||||
convert as convertxelatex,
|
|
||||||
properties as propertiesxelatex,
|
|
||||||
} from "./xelatex";
|
|
||||||
|
|
||||||
import {
|
|
||||||
convert as convertLibjxl,
|
|
||||||
properties as propertiesLibjxl,
|
|
||||||
} from "./libjxl";
|
|
||||||
|
|
||||||
import {
|
|
||||||
convert as convertresvg,
|
|
||||||
properties as propertiesresvg,
|
|
||||||
} from "./resvg";
|
|
||||||
|
|
||||||
import {
|
|
||||||
convert as convertassimp,
|
|
||||||
properties as propertiesassimp,
|
|
||||||
} from "./assimp";
|
|
||||||
|
|
||||||
import { normalizeFiletype } from "../helpers/normalizeFiletype";
|
import { normalizeFiletype } from "../helpers/normalizeFiletype";
|
||||||
|
import { convert as convertassimp, properties as propertiesassimp } from "./assimp";
|
||||||
|
import { convert as convertFFmpeg, properties as propertiesFFmpeg } from "./ffmpeg";
|
||||||
|
import { convert as convertGraphicsmagick, properties as propertiesGraphicsmagick } from "./graphicsmagick";
|
||||||
|
import { convert as convertLibjxl, properties as propertiesLibjxl } from "./libjxl";
|
||||||
|
import { convert as convertPandoc, properties as propertiesPandoc } from "./pandoc";
|
||||||
|
import { convert as convertresvg, properties as propertiesresvg } from "./resvg";
|
||||||
|
import { convert as convertImage, properties as propertiesImage } from "./vips";
|
||||||
|
import { convert as convertxelatex, properties as propertiesxelatex } from "./xelatex";
|
||||||
|
|
||||||
|
|
||||||
// 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: Record<string, {
|
const properties: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
properties: {
|
properties: {
|
||||||
from: Record<string, string[]>;
|
from: Record<string, string[]>;
|
||||||
to: Record<string, string[]>;
|
to: Record<string, string[]>;
|
||||||
options?: Record<string, Record<string, {
|
options?: Record<
|
||||||
|
string,
|
||||||
|
Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
description: string;
|
description: string;
|
||||||
type: string;
|
type: string;
|
||||||
default: number;
|
default: number;
|
||||||
}>>;
|
}
|
||||||
|
>
|
||||||
|
>;
|
||||||
};
|
};
|
||||||
converter: (
|
converter: (
|
||||||
filePath: string,
|
filePath: string,
|
||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
||||||
options?: any,
|
options?: unknown,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
) => unknown;
|
||||||
) => any;
|
}
|
||||||
}> = {
|
> = {
|
||||||
libjxl: {
|
libjxl: {
|
||||||
properties: propertiesLibjxl,
|
properties: propertiesLibjxl,
|
||||||
converter: convertLibjxl,
|
converter: convertLibjxl,
|
||||||
@@ -99,24 +76,19 @@ const properties: Record<string, {
|
|||||||
export async function mainConverter(
|
export async function mainConverter(
|
||||||
inputFilePath: string,
|
inputFilePath: string,
|
||||||
fileTypeOriginal: string,
|
fileTypeOriginal: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
convertTo: string,
|
||||||
convertTo: any,
|
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
options?: unknown,
|
||||||
options?: any,
|
|
||||||
converterName?: string,
|
converterName?: string,
|
||||||
) {
|
) {
|
||||||
const fileType = normalizeFiletype(fileTypeOriginal);
|
const fileType = normalizeFiletype(fileTypeOriginal);
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
let converterFunc: typeof properties["libjxl"]["converter"] | undefined;
|
||||||
let converterFunc: any;
|
|
||||||
// let converterName = converterName;
|
|
||||||
|
|
||||||
if (converterName) {
|
if (converterName) {
|
||||||
converterFunc = properties[converterName]?.converter;
|
converterFunc = properties[converterName]?.converter;
|
||||||
} else {
|
} else {
|
||||||
// Iterate over each converter in properties
|
// Iterate over each converter in properties
|
||||||
// biome-ignore lint/style/noParameterAssign: <explanation>
|
|
||||||
for (converterName in properties) {
|
for (converterName in properties) {
|
||||||
const converterObj = properties[converterName];
|
const converterObj = properties[converterName];
|
||||||
|
|
||||||
@@ -144,7 +116,7 @@ export async function mainConverter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await converterFunc(
|
const result = await converterFunc(
|
||||||
inputFilePath,
|
inputFilePath,
|
||||||
fileType,
|
fileType,
|
||||||
convertTo,
|
convertTo,
|
||||||
@@ -154,7 +126,13 @@ export async function mainConverter(
|
|||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`Converted ${inputFilePath} from ${fileType} to ${convertTo} successfully using ${converterName}.`,
|
`Converted ${inputFilePath} from ${fileType} to ${convertTo} successfully using ${converterName}.`,
|
||||||
|
result,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (typeof result === "string") {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
return "Done";
|
return "Done";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
@@ -190,9 +168,7 @@ for (const converterName in properties) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPossibleTargets = (
|
export const getPossibleTargets = (from: string): Record<string, string[]> => {
|
||||||
from: string,
|
|
||||||
): Record<string, string[]> => {
|
|
||||||
const fromClean = normalizeFiletype(from);
|
const fromClean = normalizeFiletype(from);
|
||||||
|
|
||||||
return possibleTargets[fromClean] || {};
|
return possibleTargets[fromClean] || {};
|
||||||
@@ -216,6 +192,7 @@ for (const converterName in properties) {
|
|||||||
}
|
}
|
||||||
possibleInputs.sort();
|
possibleInputs.sort();
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const getPossibleInputs = () => {
|
const getPossibleInputs = () => {
|
||||||
return possibleInputs;
|
return possibleInputs;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ export function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
// set xelatex here
|
// set xelatex here
|
||||||
const xelatex = ["pdf", "latex"];
|
const xelatex = ["pdf", "latex"];
|
||||||
@@ -149,7 +149,7 @@ export function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve("Done");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(`resvg "${filePath}" "${targetPath}"`, (error, stdout, stderr) => {
|
exec(`resvg "${filePath}" "${targetPath}"`, (error, stdout, stderr) => {
|
||||||
@@ -31,7 +31,7 @@ export function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve("Done");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { exec } from "node:child_process";
|
import { exec } from "node:child_process";
|
||||||
|
|
||||||
|
|
||||||
// declare possible conversions
|
// declare possible conversions
|
||||||
export const properties = {
|
export const properties = {
|
||||||
from: {
|
from: {
|
||||||
@@ -94,8 +95,8 @@ export function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
// if (fileType === "svg") {
|
// if (fileType === "svg") {
|
||||||
// const scale = options.scale || 1;
|
// const scale = options.scale || 1;
|
||||||
@@ -134,7 +135,7 @@ export function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve("Done");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export function convert(
|
|||||||
fileType: string,
|
fileType: string,
|
||||||
convertTo: string,
|
convertTo: string,
|
||||||
targetPath: string,
|
targetPath: string,
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
options?: any,
|
options?: unknown,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// const fileName: string = (targetPath.split("/").pop() as string).replace(".pdf", "")
|
// const fileName: string = (targetPath.split("/").pop() as string).replace(".pdf", "")
|
||||||
@@ -39,7 +39,7 @@ export function convert(
|
|||||||
console.error(`stderr: ${stderr}`);
|
console.error(`stderr: ${stderr}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve("success");
|
resolve("Done");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export const normalizeFiletype = (filetype: string): string => {
|
|||||||
const lowercaseFiletype = filetype.toLowerCase();
|
const lowercaseFiletype = filetype.toLowerCase();
|
||||||
|
|
||||||
switch (lowercaseFiletype) {
|
switch (lowercaseFiletype) {
|
||||||
|
case "jfif":
|
||||||
case "jpg":
|
case "jpg":
|
||||||
return "jpeg";
|
return "jpeg";
|
||||||
case "htm":
|
case "htm":
|
||||||
|
|||||||
141
src/index.tsx
141
src/index.tsx
@@ -141,7 +141,9 @@ const app = new Elysia({
|
|||||||
<main class="mx-auto w-full max-w-4xl px-4">
|
<main class="mx-auto w-full max-w-4xl px-4">
|
||||||
<h1 class="my-8 text-3xl">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-neutral-800 p-4">Create your account</header>
|
<header class="w-full bg-neutral-800 p-4">
|
||||||
|
Create your account
|
||||||
|
</header>
|
||||||
<form method="post" action="/register" class="p-4">
|
<form method="post" action="/register" class="p-4">
|
||||||
<fieldset class="mb-4 flex flex-col gap-4">
|
<fieldset class="mb-4 flex flex-col gap-4">
|
||||||
<label class="flex flex-col gap-1">
|
<label class="flex flex-col gap-1">
|
||||||
@@ -172,7 +174,10 @@ const app = new Elysia({
|
|||||||
<footer class="p-4">
|
<footer class="p-4">
|
||||||
Report any issues on{" "}
|
Report any issues on{" "}
|
||||||
<a
|
<a
|
||||||
class="text-accent-500 underline hover:text-accent-400"
|
class={`
|
||||||
|
text-accent-500 underline
|
||||||
|
hover:text-accent-400
|
||||||
|
`}
|
||||||
href="https://github.com/C4illin/ConvertX"
|
href="https://github.com/C4illin/ConvertX"
|
||||||
>
|
>
|
||||||
GitHub
|
GitHub
|
||||||
@@ -528,12 +533,21 @@ const app = new Elysia({
|
|||||||
<div class="mb-4 max-h-[50vh] overflow-y-auto scrollbar-thin">
|
<div class="mb-4 max-h-[50vh] overflow-y-auto scrollbar-thin">
|
||||||
<table
|
<table
|
||||||
id="file-list"
|
id="file-list"
|
||||||
class="w-full table-auto rounded bg-neutral-900 [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-800"
|
class={`
|
||||||
|
w-full table-auto rounded bg-neutral-900
|
||||||
|
[&_td]:p-4
|
||||||
|
[&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-800
|
||||||
|
`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id="dropzone"
|
id="dropzone"
|
||||||
class="relative flex h-48 w-full items-center justify-center rounded border border-dashed border-neutral-700 transition-all hover:border-neutral-600 [&.dragover]:border-4 [&.dragover]:border-neutral-500"
|
class={`
|
||||||
|
relative flex h-48 w-full items-center justify-center rounded border border-dashed
|
||||||
|
border-neutral-700 transition-all
|
||||||
|
[&.dragover]:border-4 [&.dragover]:border-neutral-500
|
||||||
|
hover:border-neutral-600
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
<b>Choose a file</b> or drag it here
|
<b>Choose a file</b> or drag it here
|
||||||
@@ -561,11 +575,19 @@ const app = new Elysia({
|
|||||||
class="w-full rounded bg-neutral-800 p-4"
|
class="w-full rounded bg-neutral-800 p-4"
|
||||||
/>
|
/>
|
||||||
<div class="select_container relative">
|
<div class="select_container relative">
|
||||||
<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-neutral-800 sm:h-[30vh]">
|
<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-neutral-800
|
||||||
|
sm:h-[30vh]
|
||||||
|
`}
|
||||||
|
>
|
||||||
{Object.entries(getAllTargets()).map(
|
{Object.entries(getAllTargets()).map(
|
||||||
([converter, targets]) => (
|
([converter, targets]) => (
|
||||||
<article
|
<article
|
||||||
class="convert_to_group w-full border-b border-neutral-700 p-4 flex flex-col"
|
class={`
|
||||||
|
convert_to_group flex w-full flex-col border-b border-neutral-700 p-4
|
||||||
|
`}
|
||||||
data-converter={converter}
|
data-converter={converter}
|
||||||
>
|
>
|
||||||
<header class="mb-2 w-full text-xl font-bold" safe>
|
<header class="mb-2 w-full text-xl font-bold" safe>
|
||||||
@@ -576,7 +598,10 @@ const app = new Elysia({
|
|||||||
<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 rounded bg-neutral-700 p-1 text-base hover:bg-neutral-600"
|
class={`
|
||||||
|
target rounded bg-neutral-700 p-1 text-base
|
||||||
|
hover:bg-neutral-600
|
||||||
|
`}
|
||||||
data-value={`${target},${converter}`}
|
data-value={`${target},${converter}`}
|
||||||
data-target={target}
|
data-target={target}
|
||||||
data-converter={converter}
|
data-converter={converter}
|
||||||
@@ -616,7 +641,15 @@ const app = new Elysia({
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
<input class="btn-primary w-full" type="submit" value="Convert" />
|
<input
|
||||||
|
class={`
|
||||||
|
btn-primary w-full
|
||||||
|
disabled:cursor-not-allowed disabled:opacity-50
|
||||||
|
`}
|
||||||
|
type="submit"
|
||||||
|
value="Convert"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
<script src="script.js" defer />
|
<script src="script.js" defer />
|
||||||
@@ -629,11 +662,17 @@ const app = new Elysia({
|
|||||||
({ body }) => {
|
({ body }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<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-neutral-800 sm:h-[30vh]">
|
<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-neutral-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 w-full border-b border-neutral-700 p-4 flex flex-col"
|
class="convert_to_group flex w-full flex-col border-b border-neutral-700 p-4"
|
||||||
data-converter={converter}
|
data-converter={converter}
|
||||||
>
|
>
|
||||||
<header class="mb-2 w-full text-xl font-bold" safe>
|
<header class="mb-2 w-full text-xl font-bold" safe>
|
||||||
@@ -644,7 +683,10 @@ const app = new Elysia({
|
|||||||
<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 rounded bg-neutral-700 p-1 text-base hover:bg-neutral-600"
|
class={`
|
||||||
|
target rounded bg-neutral-700 p-1 text-base
|
||||||
|
hover:bg-neutral-600
|
||||||
|
`}
|
||||||
data-value={`${target},${converter}`}
|
data-value={`${target},${converter}`}
|
||||||
data-target={target}
|
data-target={target}
|
||||||
data-converter={converter}
|
data-converter={converter}
|
||||||
@@ -713,7 +755,6 @@ const app = new Elysia({
|
|||||||
await Bun.write(`${userUploadsDir}${file.name}`, file);
|
await Bun.write(`${userUploadsDir}${file.name}`, file);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/dot-notation
|
|
||||||
await Bun.write(`${userUploadsDir}${body.file["name"]}`, body.file);
|
await Bun.write(`${userUploadsDir}${body.file["name"]}`, body.file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -893,7 +934,13 @@ 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">Results</h1>
|
<h1 class="mb-4 text-xl">Results</h1>
|
||||||
<table class="w-full table-auto rounded bg-neutral-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-800">
|
<table
|
||||||
|
class={`
|
||||||
|
w-full table-auto rounded bg-neutral-900 text-left
|
||||||
|
[&_td]:p-4
|
||||||
|
[&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-800
|
||||||
|
`}
|
||||||
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-2">Time</th>
|
<th class="px-4 py-2">Time</th>
|
||||||
@@ -912,7 +959,10 @@ const app = new Elysia({
|
|||||||
<td safe>{job.status}</td>
|
<td safe>{job.status}</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
class="text-accent-500 underline hover:text-accent-400"
|
class={`
|
||||||
|
text-accent-500 underline
|
||||||
|
hover:text-accent-400
|
||||||
|
`}
|
||||||
href={`/results/${job.id}`}
|
href={`/results/${job.id}`}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
@@ -990,9 +1040,22 @@ const app = new Elysia({
|
|||||||
<progress
|
<progress
|
||||||
max={job.num_files}
|
max={job.num_files}
|
||||||
value={files.length}
|
value={files.length}
|
||||||
class="mb-4 inline-block h-2 w-full appearance-none overflow-hidden rounded-full border-0 bg-neutral-700 bg-none text-accent-500 accent-accent-500 [&::-moz-progress-bar]:bg-neutral-700 [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:[background:none] [&[value]::-webkit-progress-value]:bg-accent-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-neutral-700 bg-none text-accent-500 accent-accent-500
|
||||||
|
[&::-moz-progress-bar]:bg-neutral-700 [&::-webkit-progress-value]:rounded-full
|
||||||
|
[&::-webkit-progress-value]:[background:none]
|
||||||
|
[&[value]::-webkit-progress-value]:bg-accent-500
|
||||||
|
[&[value]::-webkit-progress-value]:transition-[inline-size]
|
||||||
|
`}
|
||||||
/>
|
/>
|
||||||
<table class="w-full table-auto rounded bg-neutral-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-800">
|
<table
|
||||||
|
class={`
|
||||||
|
w-full table-auto rounded bg-neutral-900 text-left
|
||||||
|
[&_td]:p-4
|
||||||
|
[&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-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>
|
||||||
@@ -1008,7 +1071,10 @@ const app = new Elysia({
|
|||||||
<td safe>{file.status}</td>
|
<td safe>{file.status}</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
class="text-accent-500 underline hover:text-accent-400"
|
class={`
|
||||||
|
text-accent-500 underline
|
||||||
|
hover:text-accent-400
|
||||||
|
`}
|
||||||
href={`/download/${outputPath}${file.output_file_name}`}
|
href={`/download/${outputPath}${file.output_file_name}`}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
@@ -1016,7 +1082,10 @@ const app = new Elysia({
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
class="text-accent-500 underline hover:text-accent-400"
|
class={`
|
||||||
|
text-accent-500 underline
|
||||||
|
hover:text-accent-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}
|
||||||
>
|
>
|
||||||
@@ -1093,9 +1162,22 @@ const app = new Elysia({
|
|||||||
<progress
|
<progress
|
||||||
max={job.num_files}
|
max={job.num_files}
|
||||||
value={files.length}
|
value={files.length}
|
||||||
class="mb-4 inline-block h-2 w-full appearance-none overflow-hidden rounded-full border-0 bg-neutral-700 bg-none text-accent-500 accent-accent-500 [&::-moz-progress-bar]:bg-neutral-700 [&::-webkit-progress-value]:rounded-full [&::-webkit-progress-value]:[background:none] [&[value]::-webkit-progress-value]:bg-accent-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-neutral-700 bg-none text-accent-500 accent-accent-500
|
||||||
|
[&::-moz-progress-bar]:bg-neutral-700 [&::-webkit-progress-value]:rounded-full
|
||||||
|
[&::-webkit-progress-value]:[background:none]
|
||||||
|
[&[value]::-webkit-progress-value]:bg-accent-500
|
||||||
|
[&[value]::-webkit-progress-value]:transition-[inline-size]
|
||||||
|
`}
|
||||||
/>
|
/>
|
||||||
<table class="w-full table-auto rounded bg-neutral-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-800">
|
<table
|
||||||
|
class={`
|
||||||
|
w-full table-auto rounded bg-neutral-900 text-left
|
||||||
|
[&_td]:p-4
|
||||||
|
[&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-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>
|
||||||
@@ -1111,7 +1193,10 @@ const app = new Elysia({
|
|||||||
<td safe>{file.status}</td>
|
<td safe>{file.status}</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
class="text-accent-500 underline hover:text-accent-400"
|
class={`
|
||||||
|
text-accent-500 underline
|
||||||
|
hover:text-accent-400
|
||||||
|
`}
|
||||||
href={`/download/${outputPath}${file.output_file_name}`}
|
href={`/download/${outputPath}${file.output_file_name}`}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
@@ -1119,7 +1204,10 @@ const app = new Elysia({
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
class="text-accent-500 underline hover:text-accent-400"
|
class={`
|
||||||
|
text-accent-500 underline
|
||||||
|
hover:text-accent-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}
|
||||||
>
|
>
|
||||||
@@ -1179,7 +1267,14 @@ 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="w-full table-auto rounded bg-neutral-900 text-left [&_td]:p-4 [&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-800 [&_ul]:list-inside [&_ul]:list-disc">
|
<table
|
||||||
|
class={`
|
||||||
|
w-full table-auto rounded bg-neutral-900 text-left
|
||||||
|
[&_td]:p-4
|
||||||
|
[&_tr]:rounded [&_tr]:border-b [&_tr]:border-neutral-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>
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ const dropZone = document.getElementById("dropzone");
|
|||||||
const fileNames = [];
|
const fileNames = [];
|
||||||
let fileType;
|
let fileType;
|
||||||
|
|
||||||
dropZone.addEventListener("dragover", (e) => {
|
dropZone.addEventListener("dragover", () => {
|
||||||
dropZone.classList.add("dragover");
|
dropZone.classList.add("dragover");
|
||||||
});
|
});
|
||||||
|
|
||||||
dropZone.addEventListener("dragleave", (e) => {
|
dropZone.addEventListener("dragleave", () => {
|
||||||
dropZone.classList.remove("dragover");
|
dropZone.classList.remove("dragover");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ const updateSearchBar = () => {
|
|||||||
const convertToGroupElements = document.querySelectorAll(".convert_to_group");
|
const convertToGroupElements = document.querySelectorAll(".convert_to_group");
|
||||||
const convertToGroups = {};
|
const convertToGroups = {};
|
||||||
const convertToElement = document.querySelector("select[name='convert_to']");
|
const convertToElement = document.querySelector("select[name='convert_to']");
|
||||||
|
const convertButton = document.querySelector("input[type='submit']");
|
||||||
|
|
||||||
const showMatching = (search) => {
|
const showMatching = (search) => {
|
||||||
for (const [targets, groupElement] of Object.values(convertToGroups)) {
|
for (const [targets, groupElement] of Object.values(convertToGroups)) {
|
||||||
@@ -57,6 +58,7 @@ const updateSearchBar = () => {
|
|||||||
target.onmousedown = () => {
|
target.onmousedown = () => {
|
||||||
convertToElement.value = target.dataset.value;
|
convertToElement.value = target.dataset.value;
|
||||||
convertToInput.value = `${target.dataset.target} using ${target.dataset.converter}`;
|
convertToInput.value = `${target.dataset.target} using ${target.dataset.converter}`;
|
||||||
|
convertButton.disabled = false;
|
||||||
showMatching("");
|
showMatching("");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -68,6 +70,11 @@ const updateSearchBar = () => {
|
|||||||
showMatching(e.target.value.toLowerCase());
|
showMatching(e.target.value.toLowerCase());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
convertToInput.addEventListener("search", () => {
|
||||||
|
// when the user clears the search bar using the 'x' button
|
||||||
|
convertButton.disabled = true;
|
||||||
|
});
|
||||||
|
|
||||||
convertToInput.addEventListener("blur", (e) => {
|
convertToInput.addEventListener("blur", (e) => {
|
||||||
// Keep the popup open even when clicking on a target button
|
// Keep the popup open even when clicking on a target button
|
||||||
// for a split second to allow the click to go through
|
// for a split second to allow the click to go through
|
||||||
@@ -153,6 +160,7 @@ const setTitle = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Add a onclick for the delete button
|
// Add a onclick for the delete button
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const deleteRow = (target) => {
|
const deleteRow = (target) => {
|
||||||
const filename = target.parentElement.parentElement.children[0].textContent;
|
const filename = target.parentElement.parentElement.children[0].textContent;
|
||||||
const row = target.parentElement.parentElement;
|
const row = target.parentElement.parentElement;
|
||||||
@@ -203,7 +211,7 @@ const uploadFiles = (files) => {
|
|||||||
|
|
||||||
const formConvert = document.querySelector("form[action='/convert']");
|
const formConvert = document.querySelector("form[action='/convert']");
|
||||||
|
|
||||||
formConvert.addEventListener("submit", (e) => {
|
formConvert.addEventListener("submit", () => {
|
||||||
const hiddenInput = document.querySelector("input[name='file_names']");
|
const hiddenInput = document.querySelector("input[name='file_names']");
|
||||||
hiddenInput.value = JSON.stringify(fileNames);
|
hiddenInput.value = JSON.stringify(fileNames);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./src/**/*.{html,js,tsx,jsx,cjs,mjs}"],
|
content: ["./src/**/*.{html,js,tsx,jsx,cjs,mjs}"],
|
||||||
theme: {
|
theme: {
|
||||||
|
|||||||
Reference in New Issue
Block a user