view mrjunejune/test/snapshots/tools_latex_editor.snapshot @ 244:b8aa08503378

[tools] Add sandboxed online LaTeX editor Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Mon, 03 Aug 2026 16:56:25 -0700
parents
children 4f2b50bc78e7
line wrap: on
line source

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#544e43">
<link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
<link rel="manifest" href="/public/manifest.json">
<link rel="apple-touch-icon" href="/public/epi_all_colors.svg">

<link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font"  crossorigin>
<link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>

<!-- <link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin> -->
<!-- <link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin> -->

<!-- <link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin> -->
<link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
<link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
<link rel="preload" href="/public/epi_all_colors.svg" as="image">

<link rel="preload" href="/base.css" as="style" />
<link rel="stylesheet" href="/base.css" />

<script src="/public/pwa-register.js" defer></script>


    <title>LaTeX Editor - MrJuneJune</title>
    <link rel="stylesheet" href="/tools/latex_editor/index.css" />
    <script src="/tools/latex_editor/index.js" defer></script>
  </head>
  <body>
    <style>
  :root {
    --header-background: var(--white);
    --header-color: rgb(var(--black));
    --link-hover-accent: var(--awesome);
  }

  /* Fixed icon in top left corner */
  #themeToggle {
    position: fixed;
    top: 20px;
    left: 20px;
    background: var(--header-background);
    display: flex;
    align-items: center;
    border-radius: 50%;
    cursor: pointer;
    z-index: 1000;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    transition: transform 0.2s ease;
  }

  #themeToggle:hover {
    transform: scale(1.05);
  }

  /* Professional header */
  header {
    margin: auto;
    padding: 1.5em 1em;
    font-family: "More", sans-serif;
    box-shadow: 0 2px 8px rgba(var(--black), 5%);
    width: 720px;
    max-width: calc(100% - 2em);
    text-align: center;
  }

  header h1 {
    margin: 0;
    font-size: 1.8em;
    font-weight: 700;
    letter-spacing: -0.5px;
  }

  header h1 a {
    text-decoration: none;
    color: var(--header-color);
  }

  header h1 a::before {
    display: none;
  }

  /* Mobile responsiveness */
  @media (max-width: 720px) {
    #themeToggle {
      top: 15px;
      left: 15px;
    }

    header {
      padding: 1em;
    }

    header h1 {
      font-size: 1.5em;
    }
  }

  @media (max-width: 480px) {
    #themeToggle {
      top: 10px;
      left: 10px;
    }

    #themeToggle img {
      height: 40px;
      width: 40px;
    }

    header h1 {
      font-size: 1.3em;
    }
  }

  #logo {
    width: 300px;
  }

  /* 1. DEFINE THE DEFAULTS (Light Mode) */
  :root {
    --logo-invert: invert(0);
    --epi-grayscale: grayscale(0) brightness(1);
  }
  
  /* 2. MANUAL DARK OVERRIDE */
  html.dark {
    --logo-invert: invert(1);
    --epi-grayscale: grayscale(1);
  }
  
  /* 3. MANUAL LIGHT OVERRIDE */
  html.light-mode {
    --logo-invert: invert(0);
    --epi-grayscale: brightness(2.9) grayscale(1);
  }
  
  /* 4. SYSTEM PREFERENCE */
  @media (prefers-color-scheme: dark) {
    :root:not(.light-mode) {
      --logo-invert: invert(1);
    }
  }
  
  /* 5. APPLY TO ELEMENTS */
  #logo {
    -webkit-filter: var(--logo-invert);
    filter: var(--logo-invert);
    transition: filter 0.3s ease;
  }
  
  .epi-logo {
    -webkit-filter: var(--epi-grayscale);
    filter: var(--epi-grayscale);
    transition: filter 0.3s ease;
  }
</style>

<div id="themeToggle">
  <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
</div>

<header>
  <h1><a href="/">MrJuneJune</a></h1>
</header>
<script src="/index.js"></script>


    <main class="latex-page">
      <div class="latex-heading">
        <div>
          <h1>Online LaTeX Editor</h1>
          <p>Write LaTeX here. My server compiles it inside a locked-down sandbox and sends the PDF back to this preview.</p>
        </div>
        <div class="latex-actions">
          <label class="auto-compile">
            <input id="autoCompile" type="checkbox" checked />
            Auto compile
          </label>
          <button id="resetButton" type="button" class="secondary">Reset</button>
          <button id="compileButton" type="button">Compile PDF</button>
          <a id="downloadButton" class="button-link disabled" aria-disabled="true">Download</a>
        </div>
      </div>

      <p id="latexStatus" class="latex-status" role="status" aria-live="polite">
        Preparing your first PDF...
      </p>

      <div class="latex-workspace">
        <section class="latex-panel editor-panel" aria-labelledby="sourceHeading">
          <div class="panel-heading">
            <h2 id="sourceHeading">document.tex</h2>
            <span id="sourceSize">0 / 65,536 bytes</span>
          </div>
          <textarea id="latexSource" spellcheck="false" autocomplete="off" aria-label="LaTeX source">\documentclass[11pt]{article}
\usepackage[margin=1in]{geometry}
\usepackage{amsmath}
\usepackage{xcolor}

\title{Hello from my server}
\author{MrJuneJune}
\date{\today}

\begin{document}
\maketitle

This PDF was compiled by the custom C server behind this website.

\[
  e^{i\pi} + 1 = 0
\]

\textcolor{blue}{Edit this document and watch the preview update.}

\end{document}
</textarea>
        </section>

        <section class="latex-panel preview-panel" aria-labelledby="previewHeading">
          <div class="panel-heading">
            <h2 id="previewHeading">PDF preview</h2>
            <span>Server rendered</span>
          </div>
          <iframe
            id="pdfPreview"
            title="Compiled LaTeX PDF preview"
            src="about:blank"
          ></iframe>
          <pre id="latexDiagnostics" class="latex-diagnostics" hidden></pre>
        </section>
      </div>

      <section class="latex-notes">
        <h2>Limits</h2>
        <p>Source is capped at 64 KiB and compilation at 8 seconds. Shell commands, network access, and reads outside the isolated TeX workspace are blocked.</p>
      </section>
    </main>
    <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
  <small>&copy; 2026 June Park</small>
</div>

  </body>
</html>