chore(pre-commit) / refactor(templates): add ESLint pre-commit hook + refactor result.jinja (#379)

* chore(pre-commit) / refactor(templates): add ESLint hook + refactor `result.jinja`

* Add `eslint` to `pre-commit` hooks
* `getFileName` + `toggleFile` moved to `utils.js`
* Run linter
This commit is contained in:
Filip Christiansen 2025-07-04 18:32:34 +02:00 committed by GitHub
parent 1c80d7a69c
commit dead917060
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 334 additions and 194 deletions

View file

@ -2,65 +2,82 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
# Files
- id: check-added-large-files
description: "Prevent large files from being committed."
args: ["--maxkb=10000"]
description: 'Prevent large files from being committed.'
args: ['--maxkb=10000']
- id: check-case-conflict
description: "Check for files that would conflict in case-insensitive filesystems."
description: 'Check for files that would conflict in case-insensitive filesystems.'
- id: fix-byte-order-marker
description: "Remove utf-8 byte order marker."
description: 'Remove utf-8 byte order marker.'
- id: mixed-line-ending
description: "Replace mixed line ending."
description: 'Replace mixed line ending.'
# Links
- id: destroyed-symlinks
description: "Detect symlinks which are changed to regular files with a content of a path which that symlink was pointing to."
description: 'Detect symlinks which are changed to regular files with a content of a path which that symlink was pointing to.'
# File files for parseable syntax: python
- id: check-ast
description: 'Check for parseable syntax.'
# File and line endings
- id: end-of-file-fixer
description: "Ensure that a file is either empty, or ends with one newline."
- id: trailing-whitespace
description: "Trim trailing whitespace."
description: 'Ensure that a file is either empty, or ends with one newline.'
- id: trailing-whitespace
description: 'Trim trailing whitespace.'
# Python
- id: check-docstring-first
description: "Check a common error of defining a docstring after code."
description: 'Check a common error of defining a docstring after code.'
- id: requirements-txt-fixer
description: "Sort entries in requirements.txt."
description: 'Sort entries in requirements.txt.'
- repo: https://github.com/MarcoGorelli/absolufy-imports
rev: v0.3.1
hooks:
- id: absolufy-imports
description: "Automatically convert relative imports to absolute. (Use `args: [--never]` to revert.)"
description: 'Automatically convert relative imports to absolute. (Use `args: [--never]` to revert.)'
- repo: https://github.com/asottile/pyupgrade
rev: v3.20.0
hooks:
- id: pyupgrade
description: "Automatically upgrade syntax for newer versions."
description: 'Automatically upgrade syntax for newer versions.'
args: [--py3-plus, --py36-plus]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
- id: python-check-blanket-noqa
description: "Enforce that `noqa` annotations always occur with specific codes. Sample annotations: `# noqa: F401`, `# noqa: F401,W203`."
description: 'Enforce that `# noqa` annotations always occur with specific codes.'
- id: python-check-blanket-type-ignore
description: "Enforce that `# type: ignore` annotations always occur with specific codes. Sample annotations: `# type: ignore[attr-defined]`, `# type: ignore[attr-defined, name-defined]`."
description: 'Enforce that `# type: ignore` annotations always occur with specific codes.'
- id: python-use-type-annotations
description: "Enforce that python3.6+ type annotations are used instead of type comments."
description: 'Enforce that python3.6+ type annotations are used instead of type comments.'
- repo: https://github.com/PyCQA/isort
rev: 6.0.1
hooks:
- id: isort
description: "Sort imports alphabetically, and automatically separated into sections and by type."
description: 'Sort imports alphabetically, and automatically separated into sections and by type.'
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v9.30.1
hooks:
- id: eslint
description: 'Lint javascript files.'
files: \.js$
args: [--max-warnings=0, --fix]
additional_dependencies:
[
'eslint@9.30.1',
'@eslint/js@9.30.1',
'eslint-plugin-import@2.32.0',
'globals@16.3.0',
]
- repo: https://github.com/djlint/djLint
rev: v1.36.4
@ -71,11 +88,11 @@ repos:
rev: v0.45.0
hooks:
- id: markdownlint
description: "Lint markdown files."
args: ["--disable=line-length"]
description: 'Lint markdown files.'
args: ['--disable=line-length']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.1
rev: v0.12.2
hooks:
- id: ruff-check
- id: ruff-format
@ -97,17 +114,19 @@ repos:
additional_dependencies:
[
click>=8.0.0,
"fastapi[standard]>=0.109.1",
'fastapi[standard]>=0.109.1',
httpx,
pathspec>=0.12.1,
pydantic,
pytest-asyncio,
pytest-mock,
python-dotenv,
slowapi,
starlette>=0.40.0,
tiktoken,
pathspec,
tiktoken>=0.7.0,
uvicorn>=0.11.7,
]
- id: pylint
name: pylint for tests
files: ^tests/
@ -116,15 +135,16 @@ repos:
additional_dependencies:
[
click>=8.0.0,
"fastapi[standard]>=0.109.1",
'fastapi[standard]>=0.109.1',
httpx,
pathspec>=0.12.1,
pydantic,
pytest-asyncio,
pytest-mock,
python-dotenv,
slowapi,
starlette>=0.40.0,
tiktoken,
pathspec,
tiktoken>=0.7.0,
uvicorn>=0.11.7,
]

74
eslint.config.cjs Normal file
View file

@ -0,0 +1,74 @@
const js = require('@eslint/js');
const globals = require('globals');
const importPlugin = require('eslint-plugin-import');
module.exports = [
js.configs.recommended,
{
files: ['src/static/js/**/*.js'],
languageOptions: {
parserOptions: { ecmaVersion: 2021, sourceType: 'module' },
globals: {
...globals.browser,
changePattern: 'readonly',
copyFullDigest: 'readonly',
copyText: 'readonly',
downloadFullDigest: 'readonly',
handleSubmit: 'readonly',
posthog: 'readonly',
submitExample: 'readonly',
toggleAccessSettings: 'readonly',
toggleFile: 'readonly',
},
},
plugins: { import: importPlugin },
rules: {
// Import hygiene (eslint-plugin-import)
'import/no-extraneous-dependencies': 'error',
'import/no-unresolved': 'error',
'import/order': ['warn', { alphabetize: { order: 'asc' } }],
// Safety & bug-catchers
'consistent-return': 'error',
'default-case': 'error',
'no-implicit-globals': 'error',
'no-shadow': 'error',
// Maintainability / complexity
complexity: ['warn', 10],
'max-depth': ['warn', 4],
'max-lines': ['warn', 500],
'max-params': ['warn', 5],
// Stylistic consistency (auto-fixable)
'arrow-parens': ['error', 'always'],
curly: ['error', 'all'],
indent: ['error', 4, { SwitchCase: 2 }],
'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 2 }],
'no-multi-spaces': 'error',
'object-shorthand': ['error', 'always'],
'padding-line-between-statements': [
'warn',
{ blankLine: 'always', prev: '*', next: 'return' },
{ blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
{ blankLine: 'any', prev: ['const', 'let', 'var'], next: ['const', 'let', 'var'] },
],
'quote-props': ['error', 'consistent-as-needed'],
quotes: ['error', 'single', { avoidEscape: true }],
semi: 'error',
// Modern / performance tips
'arrow-body-style': ['warn', 'as-needed'],
'prefer-arrow-callback': 'error',
'prefer-exponentiation-operator': 'error',
'prefer-numeric-literals': 'error',
'prefer-object-has-own': 'warn',
'prefer-object-spread': 'error',
'prefer-template': 'error',
},
},
];

View file

@ -1,57 +1 @@
<script>
function getFileName(element) {
const indentSize = 4;
let path = "";
let prevIndentLevel = null;
while (element) {
const line = element.textContent;
const index = line.search(/[a-zA-Z0-9_.-]/);
const indentLevel = index / indentSize;
// Stop when we reach or go above the top-level directory
if (indentLevel <= 1) {
break;
}
// Only include directories that are one level above the previous
if (prevIndentLevel === null || indentLevel === prevIndentLevel - 1) {
const fileName = line.substring(index).trim();
path = fileName + path;
prevIndentLevel = indentLevel;
}
element = element.previousElementSibling;
}
return path;
}
function toggleFile(element) {
const patternInput = document.getElementById("pattern");
const patternFiles = patternInput.value ? patternInput.value.split(",").map(item => item.trim()) : [];
const directoryContainer = document.getElementById("directory-structure-container");
const treeLineElements = Array.from(directoryContainer.children).filter(child => child.tagName === "PRE");
// Skip the first two tree lines (header and repository name)
if (treeLineElements[0] === element || treeLineElements[1] === element) {
return;
}
element.classList.toggle('line-through');
element.classList.toggle('text-gray-500');
const fileName = getFileName(element);
const fileIndex = patternFiles.indexOf(fileName);
if (fileIndex !== -1) {
patternFiles.splice(fileIndex, 1);
} else {
patternFiles.push(fileName);
}
patternInput.value = patternFiles.join(", ");
}
</script>
<div class="mt-10" data-results></div>

View file

@ -1,15 +1,32 @@
<style type="text/tailwindcss">
@layer components {
.badge-new { @apply inline-block -rotate-6 -translate-y-1 mx-1 px-1 bg-[#FE4A60] border border-gray-900 text-white text-[10px] font-bold shadow-[2px_2px_0_0_rgba(0,0,0,1)]; }
.landing-page-title { @apply inline-block w-full relative text-center text-4xl sm:text-5xl md:text-6xl lg:text-7xl sm:pt-20 lg:pt-5 font-bold tracking-tighter; }
.intro-text { @apply text-center text-gray-600 text-lg max-w-2xl mx-auto; }
.sparkle-red { @apply absolute flex-shrink-0 h-auto w-14 sm:w-20 md:w-24 p-2 left-0 lg:ml-32 -translate-x-2 md:translate-x-10 lg:-translate-x-full -translate-y-4 sm:-translate-y-8 md:-translate-y-0 lg:-translate-y-10; }
.sparkle-green { @apply absolute flex-shrink-0 right-0 bottom-0 w-10 sm:w-16 lg:w-20 -translate-x-10 lg:-translate-x-12 translate-y-4 sm:translate-y-10 md:translate-y-2 lg:translate-y-4; }
.pattern-select { @apply min-w-max appearance-none pr-6 pl-2 py-2 bg-[#e6e8eb] border-r-[3px] border-gray-900 cursor-pointer focus:outline-none; }
.badge-new {
@apply inline-block -rotate-6 -translate-y-1 mx-1 px-1 bg-[#FE4A60] border border-gray-900 text-white text-[10px] font-bold shadow-[2px_2px_0_0_rgba(0,0,0,1)];
}
.landing-page-title {
@apply inline-block w-full relative text-center text-4xl sm:text-5xl md:text-6xl lg:text-7xl sm:pt-20 lg:pt-5 font-bold tracking-tighter;
}
.intro-text {
@apply text-center text-gray-600 text-lg max-w-2xl mx-auto;
}
.sparkle-red {
@apply absolute flex-shrink-0 h-auto w-14 sm:w-20 md:w-24 p-2 left-0 lg:ml-32 -translate-x-2 md:translate-x-10 lg:-translate-x-full -translate-y-4 sm:-translate-y-8 md:-translate-y-0 lg:-translate-y-10;
}
.sparkle-green {
@apply absolute flex-shrink-0 right-0 bottom-0 w-10 sm:w-16 lg:w-20 -translate-x-10 lg:-translate-x-12 translate-y-4 sm:translate-y-10 md:translate-y-2 lg:translate-y-4;
}
.pattern-select {
@apply min-w-max appearance-none pr-6 pl-2 py-2 bg-[#e6e8eb] border-r-[3px] border-gray-900 cursor-pointer focus:outline-none;
}
}
@layer utilities {
.no-drag { @apply pointer-events-none select-none; -webkit-user-drag: none; }
.link-bounce { @apply transition-transform hover:-translate-y-0.5; }
.no-drag {
@apply pointer-events-none select-none;
-webkit-user-drag: none;
}
.link-bounce {
@apply transition-transform hover:-translate-y-0.5;
}
}
</style>

View file

@ -1,27 +1,29 @@
function waitForStars() {
return new Promise((resolve) => {
const check = () => {
const stars = document.getElementById("github-stars");
if (stars && stars.textContent !== "0") resolve();
else setTimeout(check, 10);
const stars = document.getElementById('github-stars');
if (stars && stars.textContent !== '0') {resolve();}
else {setTimeout(check, 10);}
};
check();
});
}
document.addEventListener("DOMContentLoaded", () => {
const urlInput = document.getElementById("input_text");
const form = document.getElementById("ingestForm");
document.addEventListener('DOMContentLoaded', () => {
const urlInput = document.getElementById('input_text');
const form = document.getElementById('ingestForm');
if (urlInput && urlInput.value.trim() && form) {
// Wait for stars to be loaded before submitting
waitForStars().then(() => {
const submitEvent = new SubmitEvent("submit", {
const submitEvent = new SubmitEvent('submit', {
cancelable: true,
bubbles: true
});
Object.defineProperty(submitEvent, "target", {
Object.defineProperty(submitEvent, 'target', {
value: form,
enumerable: true
});

View file

@ -1,41 +1,42 @@
// Strike-through / un-strike file lines when the pattern-type menu flips.
function changePattern() {
const files = document.getElementsByName("tree-line");
const files = document.getElementsByName('tree-line');
files.forEach((el) => {
if (el.textContent.includes("Directory structure:")) return;
if (el.textContent.includes('Directory structure:')) {return;}
[
"line-through",
"text-gray-500",
"hover:text-inherit",
"hover:no-underline",
"hover:line-through",
"hover:text-gray-500",
'line-through',
'text-gray-500',
'hover:text-inherit',
'hover:no-underline',
'hover:line-through',
'hover:text-gray-500',
].forEach((cls) => el.classList.toggle(cls));
});
}
// Show/hide the Personal-Access-Token section when the “Private repository” checkbox is toggled.
function toggleAccessSettings() {
const container = document.getElementById("accessSettingsContainer");
const examples = document.getElementById("exampleRepositories");
const container = document.getElementById('accessSettingsContainer');
const examples = document.getElementById('exampleRepositories');
const show = document.getElementById('showAccessSettings')?.checked;
container?.classList.toggle("hidden", !show);
examples?.classList.toggle("lg:mt-0", show);
container?.classList.toggle('hidden', !show);
examples?.classList.toggle('lg:mt-0', show);
}
document.addEventListener("DOMContentLoaded", () => {
document.addEventListener('DOMContentLoaded', () => {
document
.getElementById("pattern_type")
?.addEventListener("change", () => changePattern());
.getElementById('pattern_type')
?.addEventListener('change', () => changePattern());
document
.getElementById("showAccessSettings")
?.addEventListener("change", toggleAccessSettings);
.getElementById('showAccessSettings')
?.addEventListener('change', toggleAccessSettings);
/* 3. Initial UI sync -------------------------------- */
// Initial UI sync
toggleAccessSettings();
changePattern();
});

View file

@ -1,5 +1,6 @@
function submitExample(repoName) {
const input = document.getElementById("input_text");
const input = document.getElementById('input_text');
if (input) {
input.value = repoName;
input.focus();

View file

@ -1,20 +1,24 @@
// Fetch GitHub stars
function formatStarCount(count) {
if (count >= 1000) return (count / 1000).toFixed(1) + 'k';
if (count >= 1000) {return `${ (count / 1000).toFixed(1) }k`;}
return count.toString();
}
async function fetchGitHubStars() {
try {
const res = await fetch('https://api.github.com/repos/cyclotruc/gitingest');
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
if (!res.ok) {throw new Error(`${res.status} ${res.statusText}`);}
const data = await res.json();
document.getElementById('github-stars').textContent =
formatStarCount(data.stargazers_count);
} catch (err) {
console.error('Error fetching GitHub stars:', err);
const el = document.getElementById('github-stars').parentElement;
if (el) el.style.display = 'none';
if (el) {el.style.display = 'none';}
}
}

View file

@ -1,12 +1,13 @@
/* eslint-disable */
!function (t, e) {
var o, n, p, r;
if (e.__SV) return; // already loaded
let o, n, p, r;
if (e.__SV) {return;} // already loaded
window.posthog = e;
e._i = [];
e.init = function (i, s, a) {
function g(t, e) {
var o = e.split(".");
const o = e.split(".");
if (o.length === 2) {
t = t[o[0]];
e = o[1];
@ -20,12 +21,12 @@
p.type = "text/javascript";
p.crossOrigin = "anonymous";
p.async = true;
p.src = s.api_host.replace(".i.posthog.com", "-assets.i.posthog.com") + "/static/array.js";
p.src = `${ s.api_host.replace(".i.posthog.com", "-assets.i.posthog.com") }/static/array.js`;
r = t.getElementsByTagName("script")[0];
r.parentNode.insertBefore(p, r);
var u = e;
let u = e;
if (a !== undefined) {
u = e[a] = [];
} else {
@ -34,13 +35,13 @@
u.people = u.people || [];
u.toString = function (t) {
var e = "posthog";
if (a !== "posthog") e += "." + a;
if (!t) e += " (stub)";
let e = "posthog";
if (a !== "posthog") {e += `.${ a }`;}
if (!t) {e += " (stub)";}
return e;
};
u.people.toString = function () {
return u.toString(1) + ".people (stub)";
return `${ u.toString(1) }.people (stub)`;
};
@ -60,7 +61,7 @@
"debug", "getPageViewId"
];
for (n = 0; n < o.length; n++) g(u, o[n]);
for (n = 0; n < o.length; n++) {g(u, o[n]);}
e._i.push([i, s, a]);
};

View file

@ -5,17 +5,20 @@ function copyText(className) {
if (className === 'directory-structure') {
// For directory structure, get the hidden input value
const hiddenInput = document.getElementById('directory-structure-content');
if (!hiddenInput) return;
if (!hiddenInput) {return;}
textToCopy = hiddenInput.value;
} else {
// For other elements, get the textarea value
const textarea = document.querySelector('.' + className);
if (!textarea) return;
const textarea = document.querySelector(`.${ className }`);
if (!textarea) {return;}
textToCopy = textarea.value;
}
const button = document.querySelector(`button[onclick="copyText('${className}')"]`);
if (!button) return;
if (!button) {return;}
// Copy text
navigator.clipboard.writeText(textToCopy)
@ -31,9 +34,10 @@ function copyText(className) {
button.innerHTML = originalContent;
}, 1000);
})
.catch(err => {
// Show error in button
.catch((err) => {
console.error('Failed to copy text:', err);
const originalContent = button.innerHTML;
button.innerHTML = 'Failed to copy';
setTimeout(() => {
button.innerHTML = originalContent;
@ -41,11 +45,68 @@ function copyText(className) {
});
}
function getFileName(element) {
const indentSize = 4;
let path = '';
let prevIndentLevel = null;
while (element) {
const line = element.textContent;
const index = line.search(/[a-zA-Z0-9_.-]/);
const indentLevel = index / indentSize;
// Stop when we reach or go above the top-level directory
if (indentLevel <= 1) {
break;
}
if (prevIndentLevel === null || indentLevel === prevIndentLevel - 1) {
const fileName = line.substring(index).trim();
path = fileName + path;
prevIndentLevel = indentLevel;
}
element = element.previousElementSibling;
}
return path;
}
function toggleFile(element) {
const patternInput = document.getElementById('pattern');
const patternFiles = patternInput.value
? patternInput.value.split(',').map((item) => item.trim())
: [];
const directoryContainer = document.getElementById('directory-structure-container');
const treeLineElements = Array.from(directoryContainer.children).filter(
(child) => child.tagName === 'PRE',
);
// Skip header and repository name
if (treeLineElements.slice(0, 2).includes(element)) {
return;
}
element.classList.toggle('line-through');
element.classList.toggle('text-gray-500');
const fileName = getFileName(element);
const idx = patternFiles.indexOf(fileName);
if (idx !== -1) {
patternFiles.splice(idx, 1);
} else {
patternFiles.push(fileName);
}
patternInput.value = patternFiles.join(', ');
}
function handleSubmit(event, showLoading = false) {
event.preventDefault();
const form = event.target || document.getElementById('ingestForm');
if (!form) return;
if (!form) {return;}
// Declare resultsSection before use
const resultsSection = document.querySelector('[data-results]');
@ -64,12 +125,14 @@ function handleSubmit(event, showLoading = false) {
}
const submitButton = form.querySelector('button[type="submit"]');
if (!submitButton) return;
if (!submitButton) {return;}
const formData = new FormData(form);
// Update file size
const slider = document.getElementById('file_size');
if (slider) {
formData.delete('max_file_size');
formData.append('max_file_size', slider.value);
@ -78,6 +141,7 @@ function handleSubmit(event, showLoading = false) {
// Update pattern type and pattern
const patternType = document.getElementById('pattern_type');
const pattern = document.getElementById('pattern');
if (patternType && pattern) {
formData.delete('pattern_type');
formData.delete('pattern');
@ -103,18 +167,19 @@ function handleSubmit(event, showLoading = false) {
// Submit the form to /api/ingest
fetch('/api/ingest', { method: 'POST', body: formData })
.then(response => response.json())
.then(data => {
.then((response) => response.json())
.then((data) => {
// Hide loading overlay
if (resultsSection) resultsSection.innerHTML = '';
if (resultsSection) {resultsSection.innerHTML = '';}
submitButton.disabled = false;
submitButton.innerHTML = originalContent;
if (!resultsSection) return;
if (!resultsSection) {return;}
// Handle error
if (data.error) {
resultsSection.innerHTML = `<div class='mb-6 p-4 bg-red-50 border border-red-200 rounded-lg text-red-700'>${data.error}</div>`;
return;
}
@ -194,10 +259,12 @@ function handleSubmit(event, showLoading = false) {
// Populate directory structure lines as clickable <pre> elements
const dirPre = document.getElementById('directory-structure-pre');
if (dirPre && data.tree) {
dirPre.innerHTML = '';
data.tree.split('\n').forEach(line => {
data.tree.split('\n').forEach((line) => {
const pre = document.createElement('pre');
pre.setAttribute('name', 'tree-line');
pre.className = 'cursor-pointer hover:line-through hover:text-gray-500';
pre.textContent = line;
@ -209,14 +276,17 @@ function handleSubmit(event, showLoading = false) {
// Scroll to results
resultsSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
})
.catch(error => {
.catch((error) => {
// Hide loading overlay
if (resultsSection) resultsSection.innerHTML = '';
if (resultsSection) {
resultsSection.innerHTML = '';
}
submitButton.disabled = false;
submitButton.innerHTML = originalContent;
const resultsSection = document.querySelector('[data-results]');
if (resultsSection) {
resultsSection.innerHTML = `<div class='mb-6 p-4 bg-red-50 border border-red-200 rounded-lg text-red-700'>${error}</div>`;
const errorContainer = document.querySelector('[data-results]');
if (errorContainer) {
errorContainer.innerHTML = `<div class='mb-6 p-4 bg-red-50 border border-red-200 rounded-lg text-red-700'>${error}</div>`;
}
});
}
@ -239,7 +309,8 @@ function copyFullDigest() {
setTimeout(() => {
button.innerHTML = originalText;
}, 2000);
}).catch(err => {
})
.catch((err) => {
console.error('Failed to copy text: ', err);
});
}
@ -258,8 +329,9 @@ function downloadFullDigest() {
// Create a download link
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'codebase-digest.txt';
a.download = 'digest.txt';
document.body.appendChild(a);
a.click();
@ -288,7 +360,8 @@ function logSliderToSize(position) {
const maxPosition = 500;
const maxValue = Math.log(102400); // 100 MB
const value = Math.exp(maxValue * Math.pow(position / maxPosition, 1.5));
const value = Math.exp(maxValue * (position / maxPosition)**1.5);
return Math.round(value);
}
@ -297,10 +370,11 @@ function initializeSlider() {
const slider = document.getElementById('file_size');
const sizeValue = document.getElementById('size_value');
if (!slider || !sizeValue) return;
if (!slider || !sizeValue) {return;}
function updateSlider() {
const value = logSliderToSize(slider.value);
sizeValue.textContent = formatSize(value);
slider.style.backgroundSize = `${(slider.value / slider.max) * 100}% 100%`;
}
@ -315,24 +389,18 @@ function initializeSlider() {
// Add helper function for formatting size
function formatSize(sizeInKB) {
if (sizeInKB >= 1024) {
return Math.round(sizeInKB / 1024) + 'MB';
}
return Math.round(sizeInKB) + 'kB';
return `${ Math.round(sizeInKB / 1024) }MB`;
}
// Make sure these are available globally
window.copyText = copyText;
window.handleSubmit = handleSubmit;
window.initializeSlider = initializeSlider;
window.formatSize = formatSize;
window.downloadFullDigest = downloadFullDigest;
return `${ Math.round(sizeInKB) }kB`;
}
// Add this new function
function setupGlobalEnterHandler() {
document.addEventListener('keydown', function (event) {
document.addEventListener('keydown', (event) => {
if (event.key === 'Enter' && !event.target.matches('textarea')) {
const form = document.getElementById('ingestForm');
if (form) {
handleSubmit(new Event('submit'), true);
}
@ -345,3 +413,11 @@ document.addEventListener('DOMContentLoaded', () => {
initializeSlider();
setupGlobalEnterHandler();
});
// Make sure these are available globally
window.handleSubmit = handleSubmit;
window.toggleFile = toggleFile;
window.copyText = copyText;
window.copyFullDigest = copyFullDigest;
window.downloadFullDigest = downloadFullDigest;