C4illin 1 gadu atpakaļ
vecāks
revīzija
61a75c6d36

+ 18 - 0
src/components/base.tsx

@@ -6,6 +6,24 @@ export const BaseHtml = ({ children, title = "ConvertX" }) => (
       <title>{title}</title>
       <link rel="stylesheet" href="/pico.lime.min.css" />
       <link rel="stylesheet" href="/style.css" />
+      <link
+        rel="apple-touch-icon"
+        sizes="180x180"
+        href="/apple-touch-icon.png"
+      />
+      <link
+        rel="icon"
+        type="image/png"
+        sizes="32x32"
+        href="/favicon-32x32.png"
+      />
+      <link
+        rel="icon"
+        type="image/png"
+        sizes="16x16"
+        href="/favicon-16x16.png"
+      />
+      <link rel="manifest" href="/site.webmanifest" />
       <script src="https://unpkg.com/htmx.org@1.9.12" />
     </head>
     <body>{children}</body>

+ 1 - 1
src/components/header.tsx

@@ -4,7 +4,7 @@ export const Header = ({ loggedIn }: { loggedIn?: boolean }) => {
     rightNav = (
       <ul>
         <li>
-          <a href="/results">History</a>
+          <a href="/history">History</a>
         </li>
         <li>
           <a href="/logout">Logout</a>

+ 7 - 3
src/converters/main.ts

@@ -73,8 +73,12 @@ export async function mainConverter(
 
 const possibleConversions: { [key: string]: string[] } = {};
 
-for (const from of [...propertiesImage.from, ...propertiesPandoc.from]) {
-  possibleConversions[from] = [...propertiesImage.to, ...propertiesPandoc.to];
+for (const from of propertiesImage.from) {
+  possibleConversions[from] = propertiesImage.to;
+}
+
+for (const from of propertiesPandoc.from) {
+  possibleConversions[from] = propertiesPandoc.to;
 }
 
 export const getPossibleConversions = (from: string): string[] => {
@@ -85,4 +89,4 @@ export const getPossibleConversions = (from: string): string[] => {
 
 export const getAllTargets = () => {
   return [...propertiesImage.to, ...propertiesPandoc.to];
-};
+};

+ 118 - 6
src/converters/pandoc.ts

@@ -2,16 +2,128 @@ import { exec } from "node:child_process";
 
 export const properties = {
   from: [
-    "md", "html", "docx", "pdf", "tex", "txt", "bibtex", "biblatex", "commonmark", "commonmark_x", "creole", "csljson", "csv", "tsv", "docbook", "dokuwiki", "endnotexml", "epub", "fb2", "gfm", "haddock", "ipynb", "jats", "jira", "json", "latex", "markdown", "markdown_mmd", "markdown_phpextra", "markdown_strict", "mediawiki", "man", "muse", "native", "odt", "opml", "org", "ris", "rtf", "rst", "t2t", "textile", "tikiwiki", "twiki", "vimwiki"
+    "textile",
+    "tikiwiki",
+    "tsv",
+    "twiki",
+    "typst",
+    "vimwiki",
+    "biblatex",
+    "bibtex",
+    "bits",
+    "commonmark",
+    "commonmark_x",
+    "creole",
+    "csljson",
+    "csv",
+    "djot",
+    "docbook",
+    "docx",
+    "dokuwiki",
+    "endnotexml",
+    "epub",
+    "fb2",
+    "gfm",
+    "haddock",
+    "html",
+    "ipynb",
+    "jats",
+    "jira",
+    "json",
+    "latex",
+    "man",
+    "markdown",
+    "markdown_mmd",
+    "markdown_phpextra",
+    "markdown_strict",
+    "mediawiki",
+    "muse",
+    "pandoc native",
+    "opml",
+    "org",
+    "ris",
+    "rst",
+    "rtf",
+    "t2t",
   ],
   to: [
-    "asciidoc", "asciidoctor", "beamer", "bibtex", "biblatex", "commonmark", "commonmark_x", "context", "csljson", "docbook", "docbook4", "docbook5", "docx", "dokuwiki", "epub", "epub3", "epub2", "fb2", "gfm", "haddock", "html", "html5", "html4", "icml", "ipynb", "jats_archiving", "jats_articleauthoring", "jats_publishing", "jats", "jira", "json", "latex", "man", "markdown", "markdown_mmd", "markdown_phpextra", "markdown_strict", "markua", "mediawiki", "ms", "muse", "native", "odt", "opml", "opendocument", "org", "pdf", "plain", "pptx", "rst", "rtf", "texinfo", "textile", "slideous", "slidy", "dzslides", "revealjs", "s5", "tei", "xwiki", "zimwiki"
-  ]
+    "tei",
+    "texinfo",
+    "textile",
+    "typst",
+    "xwiki",
+    "zimwiki",
+    "asciidoc",
+    "asciidoc_legacy",
+    "asciidoctor",
+    "beamer",
+    "biblatex",
+    "bibtex",
+    "chunkedhtml",
+    "commonmark",
+    "commonmark_x",
+    "context",
+    "csljson",
+    "djot",
+    "docbook",
+    "docbook4",
+    "docbook5",
+    "docx",
+    "dokuwiki",
+    "dzslides",
+    "epub",
+    "epub2",
+    "epub3",
+    "fb2",
+    "gfm",
+    "haddock",
+    "html",
+    "html4",
+    "html5",
+    "icml",
+    "ipynb",
+    "jats",
+    "jats_archiving",
+    "jats_articleauthoring",
+    "jats_publishing",
+    "jira",
+    "json",
+    "latex",
+    "man",
+    "markdown",
+    "markdown_mmd",
+    "markdown_phpextra",
+    "markdown_strict",
+    "markua",
+    "mediawiki",
+    "ms",
+    "muse",
+    "pandoc native",
+    "odt",
+    "opendocument",
+    "opml",
+    "org",
+    "pdf",
+    "plain",
+    "pptx",
+    "revealjs",
+    "rst",
+    "rtf",
+    "s5",
+    "slideous",
+    "slidy",
+  ],
 };
 
 // biome-ignore lint/suspicious/noExplicitAny: <explanation>
-export function convert(filePath: string, fileType: string, convertTo: string, targetPath: string, options?: any) {
+export function convert(
+  filePath: string,
+  fileType: string,
+  convertTo: string,
+  targetPath: string,
+  options?: any,
+) {
   return exec(
-    `pandoc ${filePath} -f ${fileType} -t ${convertTo} -o ${targetPath}`,
+    `pandoc "${filePath}" -f ${fileType} -t ${convertTo} -o "${targetPath}"`,
   );
-}
+}

+ 22 - 14
src/index.tsx

@@ -178,7 +178,20 @@ const app = new Elysia()
       };
     },
   )
-  .get("/login", () => {
+  .get("/login", async ({ jwt, redirect, cookie: { auth } }) => {
+    console.log("login handler");
+    // if already logged in, redirect to home
+    if (auth?.value) {
+      const user = await jwt.verify(auth.value);
+      console.log(user);
+
+      if (user) {
+        return redirect("/");
+      }
+
+      auth.remove();
+    }
+
     return (
       <BaseHtml title="ConvertX | Login">
         <Header />
@@ -220,15 +233,6 @@ const app = new Elysia()
   .post(
     "/login",
     async function handler({ body, set, redirect, jwt, cookie: { auth } }) {
-      // if already logged in, redirect to home
-      if (auth?.value) {
-        const user = await jwt.verify(auth.value);
-        if (user) {
-          return redirect("/");
-        }
-        auth.remove();
-      }
-
       const existingUser = (await db
         .query("SELECT * FROM users WHERE email = ?")
         .get(body.email)) as IUser;
@@ -514,7 +518,7 @@ const app = new Elysia()
       return redirect(`/results/${jobId.value}`);
     },
   )
-  .get("/histt", async ({ jwt, redirect, cookie: { auth } }) => {
+  .get("/history", async ({ jwt, redirect, cookie: { auth } }) => {
     console.log("results page");
     if (!auth?.value) {
       console.log("no auth value");
@@ -549,7 +553,7 @@ const app = new Elysia()
     return (
       <BaseHtml title="ConvertX | Results">
         <Header loggedIn />
-        <main class="container-fluid">
+        <main class="container">
           <article>
             <h1>Results</h1>
             <table>
@@ -619,7 +623,7 @@ const app = new Elysia()
       return (
         <BaseHtml title="ConvertX | Result">
           <Header loggedIn />
-          <main class="container-fluid">
+          <main class="container">
             <article>
               <div class="grid">
                 <h1>Results</h1>
@@ -690,8 +694,12 @@ const app = new Elysia()
       if (!job) {
         return redirect("/results");
       }
+      // parse from url encoded string
+      const userId = decodeURIComponent(params.userId);
+      const jobId = decodeURIComponent(params.jobId);
+      const fileName = decodeURIComponent(params.fileName);
 
-      const filePath = `${outputDir}${params.userId}/${params.jobId}/${params.fileName}`;
+      const filePath = `${outputDir}${userId}/${jobId}/${fileName}`;
       return Bun.file(filePath);
     },
   )

BIN
src/public/android-chrome-192x192.png


BIN
src/public/android-chrome-512x512.png


BIN
src/public/apple-touch-icon.png


BIN
src/public/favicon-16x16.png


BIN
src/public/favicon-32x32.png


BIN
src/public/favicon.ico


+ 13 - 3
src/public/script.js

@@ -28,9 +28,7 @@ fileInput.addEventListener("change", (e) => {
       fileType = file.name.split(".").pop();
       console.log(file.type);
       fileInput.setAttribute("accept", `.${fileType}`);
-
-      const title = document.querySelector("h1");
-      title.textContent = `Convert .${fileType}`;
+      setTitle();
 
       fetch("/conversions", {
         method: "POST",
@@ -57,6 +55,11 @@ fileInput.addEventListener("change", (e) => {
   uploadFiles(files);
 });
 
+const setTitle = () => {
+  const title = document.querySelector("h1");
+  title.textContent = `Convert ${fileType ? `.${fileType}` : "___"}`;
+};
+
 // Add a onclick for the delete button
 const deleteRow = (target) => {
   const filename = target.parentElement.parentElement.children[0].textContent;
@@ -67,6 +70,13 @@ const deleteRow = (target) => {
   const index = fileNames.indexOf(filename);
   fileNames.splice(index, 1);
 
+  // if fileNames is empty, reset fileType
+  if (fileNames.length === 0) {
+    fileType = null;
+    fileInput.removeAttribute("accept");
+    setTitle();
+  }
+
   fetch("/delete", {
     method: "POST",
     body: JSON.stringify({ filename: filename }),

+ 19 - 0
src/public/site.webmanifest

@@ -0,0 +1,19 @@
+{
+  "name": "ConvertX | Self Hosted File Converter",
+  "short_name": "ConvertX",
+  "icons": [
+    {
+      "src": "/android-chrome-192x192.png",
+      "sizes": "192x192",
+      "type": "image/png"
+    },
+    {
+      "src": "/android-chrome-512x512.png",
+      "sizes": "512x512",
+      "type": "image/png"
+    }
+  ],
+  "theme_color": "#a5d601",
+  "background_color": "#13171f",
+  "display": "standalone"
+}