Files
markdown-converter/eslint.config.js
T
amitwh 6d08c138d8 feat(preview): footnote hover preview
Hovering a footnote reference (rendered by marked-footnote as
<a data-footnote-ref href="#footnote-N">) now shows a small popover
with the footnote body text, matching the UX of Typora and Obsidian.

- src/renderer/footnote-preview.js — pure DOM module. Mounts a single
  popover once per preview pane; mouseover delegates via Element.closest()
  to the ref, lookups the matching <li id="footnote-N"> in the same pane,
  strips the backref ↩, and positions above/below the cursor with edge
  clamping. CSS.escape() fallback for non-browser environments.
- src/renderer.js — _renderPreview calls mountFootnotePreview once per
  pane (gated by a dataset marker so re-renders don't accumulate
  listeners).
- eslint.config.js — CSS + Element added to browser globals.

Tests (8 new, tests/footnote-preview.test.js): mount/unmount, delay +
timer behavior, mouseover/mouseout show/hide, dangling ref graceful
no-op, backref ↩ stripped from the displayed text, cancel-pending-show
when a new ref is hovered, idempotent remount guard.

Full suite: 69 suites, 797 tests, lint+format clean.

Amit Haridas
2026-09-14 08:56:31 +05:30

115 lines
2.8 KiB
JavaScript

/**
* ESLint Configuration for PanConverter
* Uses flat config format (ESLint 9+)
*/
module.exports = [
{
// Global ignores
ignores: [
'node_modules/**',
'dist/**',
'coverage/**',
'*.min.js'
]
},
{
// JavaScript files
files: ['**/*.js'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
globals: {
// Node.js
require: 'readonly',
module: 'readonly',
exports: 'readonly',
__dirname: 'readonly',
__filename: 'readonly',
process: 'readonly',
Buffer: 'readonly',
console: 'readonly',
setTimeout: 'readonly',
setInterval: 'readonly',
clearTimeout: 'readonly',
clearInterval: 'readonly',
// Browser
window: 'readonly',
document: 'readonly',
localStorage: 'readonly',
alert: 'readonly',
prompt: 'readonly',
confirm: 'readonly',
Event: 'readonly',
CustomEvent: 'readonly',
HTMLElement: 'readonly',
MutationObserver: 'readonly',
TextEncoder: 'readonly',
FileReader: 'readonly',
requestAnimationFrame: 'readonly',
cancelAnimationFrame: 'readonly',
navigator: 'readonly',
location: 'readonly',
fetch: 'readonly',
URL: 'readonly',
Blob: 'readonly',
Image: 'readonly',
DragEvent: 'readonly',
ClipboardEvent: 'readonly',
KeyboardEvent: 'readonly',
MouseEvent: 'readonly',
NodeList: 'readonly',
HTMLInputElement: 'readonly',
HTMLTextAreaElement: 'readonly',
getComputedStyle: 'readonly',
CSS: 'readonly',
Element: 'readonly',
// Electron
electronAPI: 'readonly',
// Libraries
marked: 'readonly',
DOMPurify: 'readonly',
hljs: 'readonly',
mermaid: 'readonly',
// Node.js global object
global: 'writable',
// Jest
jest: 'readonly',
describe: 'readonly',
test: 'readonly',
it: 'readonly',
expect: 'readonly',
beforeEach: 'readonly',
afterEach: 'readonly',
beforeAll: 'readonly',
afterAll: 'readonly'
}
},
rules: {
// Error prevention
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'no-undef': 'error',
'no-console': 'off', // Allow console for Electron apps
// Code quality
'eqeqeq': ['warn', 'always'],
'no-var': 'warn',
'prefer-const': 'warn',
// Style (handled by Prettier)
'semi': 'off',
'quotes': 'off',
'indent': 'off',
// Async handling
'no-async-promise-executor': 'warn',
'require-await': 'off',
// Security
'no-eval': 'error',
'no-implied-eval': 'error',
'no-new-func': 'error'
}
}
];