mirror of
https://github.com/firstsun-dev/git-files-sync.git
synced 2026-07-22 06:54:27 +00:00
- Conflict modal (#42): resize to min(1100px,92vw) x min(85vh,800px) flex layout, remove the 280px content height cap, and add a Diff/Local/Remote tab switcher on narrow screens (defaults to Diff). - Settings connection status (#41): show a persistent Connected/Not connected/Checking badge in the settings tab, auto-tested on open and after an 800ms debounce on token/branch/URL/owner/repo edits, updated in place (no full re-render, so typing focus is preserved). - Local ignore patterns (#40): new "Ignore patterns" setting (.gitignore- style, multi-line) applied in GitignoreManager.isIgnored() in addition to the repo's own .gitignore, covering push/pull/refresh uniformly. Closes #42, #41, #40. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YYCTyZw7gUmJ7oh1VTmAqh
76 lines
2.8 KiB
TypeScript
76 lines
2.8 KiB
TypeScript
/**
|
|
* Sets up a JSDOM environment for DOM-based tests running in the node vitest environment.
|
|
* Call `setupObsidianDOM()` inside `beforeAll`, and use `createContainer()` for fresh roots.
|
|
*/
|
|
import { JSDOM } from 'jsdom';
|
|
|
|
let dom: JSDOM;
|
|
|
|
export function setupObsidianDOM(): void {
|
|
dom = new JSDOM('<!DOCTYPE html>');
|
|
const { window } = dom;
|
|
|
|
Object.assign(globalThis, {
|
|
document: window.document,
|
|
window: window,
|
|
HTMLElement: window.HTMLElement,
|
|
HTMLInputElement: window.HTMLInputElement,
|
|
Event: window.Event,
|
|
Text: window.Text,
|
|
});
|
|
|
|
const proto = window.HTMLElement.prototype;
|
|
if ('createEl' in proto) return;
|
|
|
|
type DomOpts = { cls?: string; text?: string; type?: string };
|
|
const toOpts = (o?: DomOpts | string): DomOpts => (typeof o === 'string' ? { cls: o } : o ?? {});
|
|
|
|
function applyOpts(el: Element, o: DomOpts): void {
|
|
if (o.cls) el.className = o.cls;
|
|
if (o.text) el.textContent = o.text;
|
|
if (o.type) (el as HTMLInputElement).type = o.type;
|
|
}
|
|
|
|
Object.assign(proto, {
|
|
createEl<K extends keyof HTMLElementTagNameMap>(tag: K, opts?: DomOpts | string): HTMLElementTagNameMap[K] {
|
|
const el = window.document.createElement(tag);
|
|
applyOpts(el, toOpts(opts));
|
|
(this as HTMLElement).appendChild(el);
|
|
return el as unknown as HTMLElementTagNameMap[K];
|
|
},
|
|
createDiv(opts?: DomOpts | string): HTMLDivElement {
|
|
const el = window.document.createElement('div');
|
|
applyOpts(el, toOpts(opts));
|
|
(this as HTMLElement).appendChild(el);
|
|
return el as unknown as HTMLDivElement;
|
|
},
|
|
createSpan(opts?: DomOpts | string): HTMLSpanElement {
|
|
const el = window.document.createElement('span');
|
|
applyOpts(el, toOpts(opts));
|
|
(this as HTMLElement).appendChild(el);
|
|
return el as unknown as HTMLSpanElement;
|
|
},
|
|
addClass(cls: string): void {
|
|
(this as HTMLElement).classList.add(cls);
|
|
},
|
|
removeClass(cls: string): void {
|
|
(this as HTMLElement).classList.remove(cls);
|
|
},
|
|
hasClass(cls: string): boolean {
|
|
return (this as HTMLElement).classList.contains(cls);
|
|
},
|
|
toggleClass(cls: string, value: boolean): void {
|
|
(this as HTMLElement).classList.toggle(cls, value);
|
|
},
|
|
setText(text: string): void {
|
|
(this as HTMLElement).textContent = text;
|
|
},
|
|
empty(): void {
|
|
(this as HTMLElement).replaceChildren();
|
|
},
|
|
});
|
|
}
|
|
|
|
export function createContainer(): HTMLElement {
|
|
return dom.window.document.createElement('div') as unknown as HTMLElement;
|
|
}
|