feat(ascii-art): standalone window uses controller + searchable picker + copy/save/insert

Amit Haridas
This commit is contained in:
2026-09-14 21:05:24 +05:30
parent 38bc2b2bc5
commit 8c162c1714
+16 -394
View File
@@ -262,14 +262,15 @@
/> />
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="form-label">Style</label> <label class="form-label">Font</label>
<select id="font-style" class="form-select"> <input
<option value="standard">Standard</option> type="text"
<option value="banner">Banner</option> id="font-search"
<option value="block">Block</option> class="form-input"
<option value="bubble">Bubble</option> placeholder="Search fonts…"
<option value="digital">Digital</option> autocomplete="off"
</select> />
<select id="font-picker" class="form-select" size="8"></select>
</div> </div>
</div> </div>
@@ -350,6 +351,10 @@
<div class="section"> <div class="section">
<div class="section-title">Preview</div> <div class="section-title">Preview</div>
<div
id="ascii-warning"
style="display: none; color: #e5461f; margin-bottom: 8px; font-size: 0.8rem"
></div>
<div class="preview-container"> <div class="preview-container">
<div id="preview" class="preview-content"></div> <div id="preview" class="preview-content"></div>
</div> </div>
@@ -358,394 +363,11 @@
<div class="footer"> <div class="footer">
<button class="btn btn-secondary" id="btn-generate">Generate Preview</button> <button class="btn btn-secondary" id="btn-generate">Generate Preview</button>
<button class="btn btn-secondary" id="btn-copy">Copy to Clipboard</button>
<button class="btn btn-secondary" id="btn-save">Save to File</button>
<button class="btn btn-primary" id="btn-insert">Insert to Editor</button> <button class="btn btn-primary" id="btn-insert">Insert to Editor</button>
</div> </div>
<script> <script src="../renderer/ascii-controller.js"></script>
// ASCII Art Generator Logic
const FONTS = {
standard: {
height: 5,
chars: {
A: [' /\\ ', ' / \\ ', '/----\\', '| |', '| |'],
B: ['|----\\', '| |', '|----/', '| \\', '|----/'],
C: ['/----\\', '| ', '| ', '| ', '\\----/'],
D: ['|----\\', '| |', '| |', '| |', '|----/'],
E: ['|----', '| ', '|--- ', '| ', '|----'],
F: ['|----', '| ', '|--- ', '| ', '| '],
G: ['/----\\', '| ', '| |--\\', '| |', '\\----/'],
H: ['| |', '| |', '|----/', '| |', '| |'],
I: ['|---|', ' | ', ' | ', ' | ', '|---|'],
J: [' |', ' |', ' |', '| |', '\\---/'],
K: ['| /', '| / ', '|-- ', '| \\ ', '| \\'],
L: ['| ', '| ', '| ', '| ', '|----'],
M: ['|\\ /|', '| \\/ |', '| |', '| |', '| |'],
N: ['|\\ |', '| \\ |', '| \\ |', '| \\|', '| |'],
O: ['/----\\', '| |', '| |', '| |', '\\----/'],
P: ['|----\\', '| |', '|----/', '| ', '| '],
Q: ['/----\\', '| |', '| \\ |', '| \\|', '\\----\\'],
R: ['|----\\', '| |', '|----/', '| \\ ', '| \\ '],
S: ['/----\\', '| ', '\\----\\', ' |', '\\----/'],
T: ['-----', ' | ', ' | ', ' | ', ' | '],
U: ['| |', '| |', '| |', '| |', '\\----/'],
V: ['| |', '| |', ' \\ / ', ' \\/ ', ' '],
W: ['| |', '| |', '| |', '| /\\ |', '|/ \\|'],
X: ['\\ /', ' \\ / ', ' \\/ ', ' /\\ ', ' / \\ '],
Y: ['\\ /', ' \\ / ', ' | ', ' | ', ' | '],
Z: ['-----', ' / ', ' / ', ' / ', '-----'],
' ': [' ', ' ', ' ', ' ', ' '],
0: ['/---\\', '| |', '| / |', '|/ |', '\\---/'],
1: [' /| ', ' / | ', ' | ', ' | ', ' ----'],
2: ['/---\\', ' |', ' ---/', '/ ', '-----'],
3: ['----\\', ' |', ' ---/', ' |', '----/'],
4: ['| |', '| |', '-----', ' |', ' |'],
5: ['-----', '| ', '----\\', ' |', '----/'],
6: ['/----', '| ', '|---\\', '| |', '\\---/'],
7: ['-----', ' / ', ' / ', ' / ', '/ '],
8: ['/---\\', '| |', ' --- ', '| |', '\\---/'],
9: ['/---\\', '| |', '\\----', ' |', '----/'],
},
},
banner: {
height: 7,
chars: {
A: [
' ##### ',
' ## ##',
'## ##',
'#########',
'## ##',
'## ##',
'## ##',
],
B: [
'######## ',
'## ##',
'## ##',
'######## ',
'## ##',
'## ##',
'######## ',
],
C: [' ###### ', '## ##', '## ', '## ', '## ', '## ##', ' ###### '],
D: [
'######## ',
'## ##',
'## ##',
'## ##',
'## ##',
'## ##',
'######## ',
],
E: ['########', '## ', '## ', '###### ', '## ', '## ', '########'],
F: ['########', '## ', '## ', '###### ', '## ', '## ', '## '],
G: [' ###### ', '## ##', '## ', '## ####', '## ##', '## ##', ' ###### '],
H: [
'## ##',
'## ##',
'## ##',
'#########',
'## ##',
'## ##',
'## ##',
],
I: ['####', ' ## ', ' ## ', ' ## ', ' ## ', ' ## ', '####'],
J: [' ##', ' ##', ' ##', ' ##', '## ##', '## ##', ' ###### '],
K: ['## ##', '## ## ', '## ## ', '##### ', '## ## ', '## ## ', '## ##'],
L: ['## ', '## ', '## ', '## ', '## ', '## ', '########'],
M: [
'## ##',
'### ###',
'#### ####',
'## ### ##',
'## ##',
'## ##',
'## ##',
],
N: ['## ##', '### ##', '#### ##', '## ## ##', '## ####', '## ###', '## ##'],
O: [
' ####### ',
'## ##',
'## ##',
'## ##',
'## ##',
'## ##',
' ####### ',
],
P: [
'######## ',
'## ##',
'## ##',
'######## ',
'## ',
'## ',
'## ',
],
Q: [
' ####### ',
'## ##',
'## ##',
'## ##',
'## ## ##',
'## ## ',
' ##### ##',
],
R: [
'######## ',
'## ##',
'## ##',
'######## ',
'## ## ',
'## ## ',
'## ##',
],
S: [' ###### ', '## ##', '## ', ' ###### ', ' ##', '## ##', ' ###### '],
T: ['########', ' ## ', ' ## ', ' ## ', ' ## ', ' ## ', ' ## '],
U: [
'## ##',
'## ##',
'## ##',
'## ##',
'## ##',
'## ##',
' ####### ',
],
V: [
'## ##',
'## ##',
'## ##',
'## ##',
' ## ## ',
' ## ## ',
' ### ',
],
W: [
'## ##',
'## ## ##',
'## ## ##',
'## ## ##',
'## ## ##',
'## ## ##',
' ### ### ',
],
X: [
'## ##',
' ## ## ',
' ## ## ',
' ### ',
' ## ## ',
' ## ## ',
'## ##',
],
Y: ['## ##', ' ## ## ', ' #### ', ' ## ', ' ## ', ' ## ', ' ## '],
Z: ['########', ' ## ', ' ## ', ' ## ', ' ## ', ' ## ', '########'],
' ': [' ', ' ', ' ', ' ', ' ', ' ', ' '],
0: [' ###### ', '## ##', '## ##', '## ##', '## ##', '## ##', ' ###### '],
1: [' ## ', ' #### ', ' ## ', ' ## ', ' ## ', ' ## ', ' ###### '],
2: [' ###### ', '## ##', ' ## ', ' ## ', ' ## ', ' ## ', '########'],
3: [' ###### ', '## ##', ' ## ', ' #### ', ' ## ', '## ##', ' ###### '],
4: [' ## ', ' ### ', ' # ## ', ' # ## ', '########', ' ## ', ' ## '],
5: ['########', '## ', '####### ', ' ##', ' ##', '## ##', ' ###### '],
6: [' ###### ', '## ', '####### ', '## ##', '## ##', '## ##', ' ###### '],
7: ['########', '## ## ', ' ## ', ' ## ', ' ## ', ' ## ', ' ## '],
8: [' ###### ', '## ##', '## ##', ' ###### ', '## ##', '## ##', ' ###### '],
9: [' ###### ', '## ##', '## ##', ' #######', ' ##', '## ##', ' ###### '],
},
},
block: {
height: 6,
chars: {
A: ['█████╗ ', '██╔══██╗', '███████║', '██╔══██║', '██║ ██║', '╚═╝ ╚═╝'],
B: ['██████╗ ', '██╔══██╗', '██████╔╝', '██╔══██╗', '██████╔╝', '╚═════╝ '],
C: ['█████╗ ', '██╔══██╗', '██║ ', '██║ ', '╚█████╔╝', ' ╚════╝ '],
D: ['██████╗ ', '██╔══██╗', '██║ ██║', '██║ ██║', '██████╔╝', '╚═════╝ '],
E: ['███████╗', '██╔════╝', '█████╗ ', '██╔══╝ ', '███████╗', '╚══════╝'],
F: ['███████╗', '██╔════╝', '█████╗ ', '██╔══╝ ', '██║ ', '╚═╝ '],
G: ['█████╗ ', '██╔══██╗', '██║ ███', '██║ ██', '╚█████╔╝', ' ╚════╝ '],
H: ['██╗ ██╗', '██║ ██║', '███████║', '██╔══██║', '██║ ██║', '╚═╝ ╚═╝'],
I: ['██╗', '██║', '██║', '██║', '██║', '╚═╝'],
J: [' ██╗', ' ██║', ' ██║', '██ ██║', '╚████╔╝', ' ╚═══╝ '],
K: ['██╗ ██╗', '██║ ██╔╝', '█████╔╝ ', '██╔═██╗ ', '██║ ██╗', '╚═╝ ╚═╝'],
L: ['██╗ ', '██║ ', '██║ ', '██║ ', '███████╗', '╚══════╝'],
M: [
'███╗ ███╗',
'████╗ ████║',
'██╔████╔██║',
'██║╚██╔╝██║',
'██║ ╚═╝ ██║',
'╚═╝ ╚═╝',
],
N: ['███╗ ██╗', '████╗ ██║', '██╔██╗ ██║', '██║╚██╗██║', '██║ ╚████║', '╚═╝ ╚═══╝'],
O: ['█████╗ ', '██╔══██╗', '██║ ██║', '██║ ██║', '╚█████╔╝', ' ╚════╝ '],
P: ['██████╗ ', '██╔══██╗', '██████╔╝', '██╔═══╝ ', '██║ ', '╚═╝ '],
Q: ['█████╗ ', '██╔══██╗', '██║ ██║', '██║ ██║', '╚██████╗', ' ╚═══██╝'],
R: ['██████╗ ', '██╔══██╗', '██████╔╝', '██╔══██╗', '██║ ██║', '╚═╝ ╚═╝'],
S: ['█████╗ ', '██╔══╝ ', '█████╗ ', '╚══██║ ', '█████║ ', '╚════╝ '],
T: ['████████╗', '╚══██╔══╝', ' ██║ ', ' ██║ ', ' ██║ ', ' ╚═╝ '],
U: ['██╗ ██╗', '██║ ██║', '██║ ██║', '██║ ██║', '╚█████╔╝', ' ╚════╝ '],
V: ['██╗ ██╗', '██║ ██║', '██║ ██║', '╚██╗ ██╔╝', ' ╚████╔╝ ', ' ╚═══╝ '],
W: ['██╗ ██╗', '██║ ██║', '██║ █╗ ██║', '██║███╗██║', '╚███╔███╔╝', ' ╚══╝╚══╝ '],
X: ['██╗ ██╗', '╚██╗██╔╝', ' ╚███╔╝ ', ' ██╔██╗ ', '██╔╝ ██╗', '╚═╝ ╚═╝'],
Y: ['██╗ ██╗', '╚██╗ ██╔╝', ' ╚████╔╝ ', ' ╚██╔╝ ', ' ██║ ', ' ╚═╝ '],
Z: ['███████╗', '╚════██║', ' ███╔═╝', ' ██╔══╝ ', '███████╗', '╚══════╝'],
' ': [' ', ' ', ' ', ' ', ' ', ' '],
},
},
};
const TEMPLATES = {
'arrow-right':
' ┌─────────────────────┐\n──▶│ Process or Action │──▶\n └─────────────────────┘',
'arrow-down':
' │\n ▼\n┌───────────────┐\n│ Process │\n└───────────────┘\n │\n ▼',
decision:
' ╱╲\n ╱ ╲\n ╱ ? ╲\n ╱ ╲\n ╱────────╲\n ╱ ╲\n YES NO\n │ │\n ▼ ▼',
process:
'┌─────┐ ┌─────┐ ┌─────┐\n│ 1 │──▶│ 2 │──▶│ 3 │\n└─────┘ └─────┘ └─────┘',
flowchart:
'┌─────────────┐\n│ START │\n└──────┬──────┘\n │\n ▼\n┌─────────────┐\n│ Process A │\n└──────┬──────┘\n │\n ▼\n ╱────────╲\n ╱ Decision ╲\n ╲ ? ╱\n ╲────────╱\n │ │\n YES NO\n │ │\n ▼ ▼\n┌──────┐ ┌──────┐\n│ B │ │ C │\n└──────┘ └──────┘',
sequence:
' User System Database\n │ │ │\n │ Request │ │\n ├──────────►│ │\n │ │ Query │\n │ ├──────────►│\n │ │ │\n │ │ Result │\n │ │◄──────────┤\n │ Response │ │\n │◄──────────┤ │\n │ │ │',
network:
' ┌─────────┐\n │ Server │\n └────┬────┘\n │\n ┌─────────┼─────────┐\n │ │ │\n┌────┴────┐ ┌──┴──┐ ┌────┴────┐\n│ Client1 │ │ DB │ │ Client2 │\n└─────────┘ └─────┘ └─────────┘',
hierarchy:
' ┌─────────┐\n │ CEO │\n └────┬────┘\n ┌─────────┼─────────┐\n │ │ │\n ┌───┴───┐ ┌───┴───┐ ┌───┴───┐\n │ VP1 │ │ VP2 │ │ VP3 │\n └───┬───┘ └───┬───┘ └───┬───┘\n │ │ │\n ┌───┴───┐ ┌───┴───┐ ┌───┴───┐\n │ Team1 │ │ Team2 │ │ Team3 │\n └───────┘ └───────┘ └───────┘',
header:
'╔════════════════════════════════════╗\n║ SECTION TITLE ║\n╚════════════════════════════════════╝',
note: '┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n┃ NOTE: ┃\n┃ This is an important note ┃\n┃ that requires attention! ┃\n┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛',
warning:
'╔════════════════════════════════════╗\n║ ⚠️ WARNING ║\n║ ║\n║ Critical information here! ║\n╚════════════════════════════════════╝',
info: '╭────────────────────────────────────╮\n│ ℹ️ INFO │\n│ │\n│ Helpful information here. │\n╰────────────────────────────────────╯',
divider: '════════════════════════════════════════',
separator:
'╭──────────────────────────────────────╮\n│ │\n╰──────────────────────────────────────╯',
banner:
'★══════════════════════════════════════★\n║ YOUR TITLE HERE ║\n★══════════════════════════════════════★',
checklist:
'☐ Task 1 - Not completed\n☑ Task 2 - Completed \n☐ Task 3 - Not completed\n☐ Task 4 - Not completed',
};
const BOX_STYLES = {
single: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' },
double: { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' },
rounded: { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' },
bold: { tl: '┏', tr: '┓', bl: '┗', br: '┛', h: '━', v: '┃' },
ascii: { tl: '+', tr: '+', bl: '+', br: '+', h: '-', v: '|' },
};
let currentMode = 'text';
let currentTemplate = null;
// Mode switching
document.querySelectorAll('.mode-tab').forEach((tab) => {
tab.addEventListener('click', () => {
document.querySelectorAll('.mode-tab').forEach((t) => t.classList.remove('active'));
tab.classList.add('active');
currentMode = tab.dataset.mode;
document.querySelectorAll('.mode-section').forEach((s) => s.classList.remove('active'));
document.getElementById(currentMode + '-mode').classList.add('active');
generatePreview();
});
});
// Template selection
document.querySelectorAll('.template-btn').forEach((btn) => {
btn.addEventListener('click', () => {
document.querySelectorAll('.template-btn').forEach((b) => b.classList.remove('active'));
btn.classList.add('active');
currentTemplate = btn.dataset.template;
generatePreview();
});
});
// Generate text banner
function generateTextBanner(text, style) {
const font = FONTS[style] || FONTS.standard;
const lines = Array(font.height).fill('');
for (const char of text.toUpperCase()) {
const charArt = font.chars[char] || font.chars[' '];
if (charArt) {
for (let i = 0; i < font.height; i++) {
lines[i] += charArt[i] + ' ';
}
}
}
return lines.join('\n');
}
// Generate box
function generateBox(text, style, padding) {
const box = BOX_STYLES[style] || BOX_STYLES.single;
const lines = text.split('\n');
const maxLen = Math.max(...lines.map((l) => l.length)) + padding * 2;
let result = box.tl + box.h.repeat(maxLen + 2) + box.tr + '\n';
// Add padding lines at top
for (let i = 0; i < Math.floor(padding / 2); i++) {
result += box.v + ' '.repeat(maxLen + 2) + box.v + '\n';
}
// Add text lines
for (const line of lines) {
const paddedLine = ' '.repeat(padding) + line.padEnd(maxLen - padding) + ' ';
result += box.v + ' ' + paddedLine + box.v + '\n';
}
// Add padding lines at bottom
for (let i = 0; i < Math.floor(padding / 2); i++) {
result += box.v + ' '.repeat(maxLen + 2) + box.v + '\n';
}
result += box.bl + box.h.repeat(maxLen + 2) + box.br;
return result;
}
// Generate preview
function generatePreview() {
let result = '';
if (currentMode === 'text') {
const text = document.getElementById('text-input').value || 'HELLO';
const style = document.getElementById('font-style').value;
result = generateTextBanner(text, style);
} else if (currentMode === 'box') {
const text = document.getElementById('box-text').value || 'Your text here';
const style = document.getElementById('box-style').value;
const padding = parseInt(document.getElementById('box-padding').value) || 2;
result = generateBox(text, style, padding);
} else if (currentMode === 'templates') {
result = currentTemplate ? TEMPLATES[currentTemplate] : 'Select a template...';
}
document.getElementById('preview').textContent = result;
}
// Event listeners for live preview
document.getElementById('text-input').addEventListener('input', generatePreview);
document.getElementById('font-style').addEventListener('change', generatePreview);
document.getElementById('box-text').addEventListener('input', generatePreview);
document.getElementById('box-style').addEventListener('change', generatePreview);
document.getElementById('box-padding').addEventListener('input', generatePreview);
document.getElementById('btn-generate').addEventListener('click', generatePreview);
document.getElementById('btn-insert').addEventListener('click', () => {
const content = document.getElementById('preview').textContent;
if (content && window.electronAPI) {
// Wrap in code block for markdown
const wrapped = '```\n' + content + '\n```';
window.electronAPI.send('insert-generated-content', wrapped);
window.close();
}
});
// Initial preview
generatePreview();
</script>
</body> </body>
</html> </html>