Repository navigation
Expand file tree
/
Copy pathquick.js
More file actions
138 lines (127 loc) · 4.1 KB
/
Copy pathquick.js
File metadata and controls
138 lines (127 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* Iconopolis Quick Search — the Spotlight-style panel. */
const $ = (id) => document.getElementById(id);
const COLS = 8;
const MAXQ = 40;
let sets = [];
let results = [];
let sel = 0;
let settings = null;
let dragPrep = null;
const cache = new Map();
const key = (it) => `${it.prefix}:${it.name}`;
(async function boot() {
const idx = JSON.parse(await window.vault.getIndex());
sets = idx.sets;
})();
window.vault.onQuickShown(async () => {
settings = await window.vault.loadSettings() || {};
$('qinput').value = '';
results = [];
sel = 0;
render();
$('qinput').focus();
});
function effColor() {
const c = settings?.color || 'auto';
return c === 'auto' ? '#000000' : c;
}
function styledSVG(svg) {
return composeStyled(exportSVG(svg, effColor()), settings?.style);
}
async function ensureSvgs(list) {
const need = new Map();
for (const it of list) {
if (!cache.has(key(it))) {
if (!need.has(it.prefix)) need.set(it.prefix, []);
need.get(it.prefix).push(it.name);
}
}
await Promise.all([...need.entries()].map(async ([prefix, names]) => {
const out = await window.vault.renderIcons(prefix, names);
for (const [name, svg] of Object.entries(out)) cache.set(`${prefix}:${name}`, svg);
}));
}
function svgEl(text) {
return document.importNode(new DOMParser().parseFromString(text, 'image/svg+xml').documentElement, true);
}
async function render() {
const grid = $('qgrid');
grid.replaceChildren();
$('qbadge').textContent = results.length ? `${results.length}${results.length >= MAXQ ? '+' : ''}` : '';
if (!results.length) {
const empty = document.createElement('div');
empty.id = 'qempty';
empty.textContent = $('qinput').value.trim() ? 'No icons found' : 'Type to search 375,000+ icons';
grid.appendChild(empty);
return;
}
await ensureSvgs(results);
results.forEach((it, i) => {
const svg = cache.get(key(it));
if (!svg) return;
const b = document.createElement('button');
b.className = 'qcell' + (i === sel ? ' sel' : '');
b.title = `${it.name} · ${it.prefix}`;
b.draggable = true;
b.appendChild(svgEl(svg));
b.addEventListener('click', () => { sel = i; copySelected(); });
b.addEventListener('mousedown', () => prepDrag(it));
b.addEventListener('dragstart', (e) => onDrag(e, it));
grid.appendChild(b);
});
}
let timer;
$('qinput').addEventListener('input', () => {
clearTimeout(timer);
timer = setTimeout(() => {
results = searchIcons(sets, $('qinput').value, MAXQ);
sel = 0;
render();
}, 120);
});
async function copySelected() {
const it = results[sel];
if (!it) return;
const svg = cache.get(key(it));
const final = styledSVG(svg);
const png = await svgToPNG(final, Math.max(settings?.pngSize || 256, 256));
await window.vault.copyIcon({
svg: final,
pngDataURL: png,
includeSVG: (settings?.format || 'svg') !== 'png',
});
window.vault.hideQuick();
}
function prepDrag(it) {
const svg = cache.get(key(it));
if (!svg) return;
const size = (settings?.format === 'png') ? (settings?.pngSize || 256) : 128;
dragPrep = { k: key(it), promise: svgToPNG(styledSVG(svg), size).catch(() => null) };
}
async function onDrag(e, it) {
e.preventDefault();
const svg = cache.get(key(it));
let png = dragPrep?.k === key(it) ? await dragPrep.promise : null;
if (!png) png = await svgToPNG(styledSVG(svg), 128).catch(() => null);
if (!png) return;
window.vault.startDrag({
name: it.name,
format: settings?.format || 'svg',
svg: styledSVG(svg),
pngDataURL: png,
});
}
window.addEventListener('keydown', (e) => {
if (e.key === 'Escape') { window.vault.hideQuick(); return; }
if (!results.length) return;
const move = { ArrowRight: 1, ArrowLeft: -1, ArrowDown: COLS, ArrowUp: -COLS }[e.key];
if (move !== undefined) {
e.preventDefault();
sel = Math.max(0, Math.min(results.length - 1, sel + move));
document.querySelectorAll('.qcell').forEach((c, i) => c.classList.toggle('sel', i === sel));
document.querySelector('.qcell.sel')?.scrollIntoView({ block: 'nearest' });
} else if (e.key === 'Enter') {
e.preventDefault();
copySelected();
}
});