feat: add related icons section to modal
- Add "Maybe Related" section showing icons with similar names - Find related icons by base name matching (e.g., time-check → time-delete) - Add icons to modal section labels (settings-sliders, link) - Style related icons grid with hover effects Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1030,6 +1030,14 @@ body {
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
letter-spacing: 0.6px;
|
letter-spacing: 0.6px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
& .fi {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--accent-primary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-variations {
|
.modal-variations {
|
||||||
@@ -1038,6 +1046,48 @@ body {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.related-icons {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-icon {
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 8px;
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
transition: var(--transition);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--bg-elevated);
|
||||||
|
border-color: var(--accent-primary);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
|
|
||||||
|
& .related-icon-symbol {
|
||||||
|
color: var(--accent-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .related-icon-symbol {
|
||||||
|
font-size: 20px;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
& .related-icon-name {
|
||||||
|
font-size: 9px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-weight: 500;
|
||||||
|
word-break: break-all;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.modal-var {
|
.modal-var {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 10px 6px;
|
padding: 10px 6px;
|
||||||
@@ -1374,6 +1424,10 @@ body {
|
|||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.related-icons {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
.modal-actions-inline {
|
.modal-actions-inline {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
+6
-1
@@ -135,10 +135,15 @@
|
|||||||
|
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-section">
|
<div class="modal-section">
|
||||||
<div class="modal-label">All Variations</div>
|
<div class="modal-label"><span class="fi fi-rs-settings-sliders"></span> All Variations</div>
|
||||||
<div class="modal-variations" id="modalVariations"></div>
|
<div class="modal-variations" id="modalVariations"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-section" id="relatedSection" style="display:none">
|
||||||
|
<div class="modal-label"><span class="fi fi-rs-link"></span> Maybe Related</div>
|
||||||
|
<div class="related-icons" id="relatedIcons"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button class="modal-btn" id="modalClose">
|
<button class="modal-btn" id="modalClose">
|
||||||
<span class="fi fi-rs-cross"></span> Close <span class="btn-key">Esc</span>
|
<span class="fi fi-rs-cross"></span> Close <span class="btn-key">Esc</span>
|
||||||
|
|||||||
+72
@@ -237,6 +237,53 @@ function animateGrid() {
|
|||||||
function animateModal() {
|
function animateModal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findRelatedIcons(currentName, currentPrefix, limit = 12) {
|
||||||
|
const parts = currentName.split('-');
|
||||||
|
const baseName = parts[0];
|
||||||
|
|
||||||
|
const relatedScores = new Map();
|
||||||
|
|
||||||
|
for (const prefix of Object.keys(iconsByPrefix)) {
|
||||||
|
for (const icon of iconsByPrefix[prefix]) {
|
||||||
|
if (icon.name === currentName) continue;
|
||||||
|
|
||||||
|
const iconParts = icon.name.split('-');
|
||||||
|
const iconBase = iconParts[0];
|
||||||
|
|
||||||
|
let score = 0;
|
||||||
|
|
||||||
|
if (iconBase === baseName) {
|
||||||
|
score += 50;
|
||||||
|
|
||||||
|
const remainingParts = iconParts.slice(1).join('-');
|
||||||
|
const currentRemaining = parts.slice(1).join('-');
|
||||||
|
|
||||||
|
if (remainingParts === currentRemaining) {
|
||||||
|
score += 20;
|
||||||
|
}
|
||||||
|
} else if (icon.name.includes(baseName) || baseName.includes(iconBase)) {
|
||||||
|
score += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix === currentPrefix) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > 0) {
|
||||||
|
const existing = relatedScores.get(icon.name) || { score: 0, prefixes: new Set() };
|
||||||
|
existing.score = Math.max(existing.score, score);
|
||||||
|
existing.prefixes.add(prefix);
|
||||||
|
relatedScores.set(icon.name, existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(relatedScores.entries())
|
||||||
|
.sort((a, b) => b[1].score - a[1].score)
|
||||||
|
.slice(0, limit)
|
||||||
|
.map(([name, data]) => ({ name, prefixes: Array.from(data.prefixes) }));
|
||||||
|
}
|
||||||
|
|
||||||
function renderIcons() {
|
function renderIcons() {
|
||||||
const prefix = getCurrentPrefix();
|
const prefix = getCurrentPrefix();
|
||||||
const filtered = getFilteredIcons();
|
const filtered = getFilteredIcons();
|
||||||
@@ -300,6 +347,8 @@ function showModal(name, currentPrefix) {
|
|||||||
const modalTitle = document.getElementById('modalTitle');
|
const modalTitle = document.getElementById('modalTitle');
|
||||||
const modalSubtitle = document.getElementById('modalSubtitle');
|
const modalSubtitle = document.getElementById('modalSubtitle');
|
||||||
const modalVariations = document.getElementById('modalVariations');
|
const modalVariations = document.getElementById('modalVariations');
|
||||||
|
const relatedSection = document.getElementById('relatedSection');
|
||||||
|
const relatedIcons = document.getElementById('relatedIcons');
|
||||||
|
|
||||||
modalTitle.textContent = name;
|
modalTitle.textContent = name;
|
||||||
|
|
||||||
@@ -337,6 +386,29 @@ function showModal(name, currentPrefix) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const related = findRelatedIcons(name, currentPrefix);
|
||||||
|
if (related.length > 0) {
|
||||||
|
relatedSection.style.display = 'block';
|
||||||
|
relatedIcons.innerHTML = related.map(({ name: relatedName, prefixes }) => {
|
||||||
|
const relatedPrefix = prefixes.includes(currentPrefix) ? currentPrefix : prefixes[0];
|
||||||
|
const relatedClassName = `fi-${relatedPrefix}-${relatedName}`;
|
||||||
|
return `
|
||||||
|
<div class="related-icon" data-name="${relatedName}" data-prefix="${relatedPrefix}">
|
||||||
|
<span class="fi ${relatedClassName} related-icon-symbol"></span>
|
||||||
|
<div class="related-icon-name">${relatedName}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
relatedIcons.querySelectorAll('.related-icon').forEach(el => {
|
||||||
|
el.addEventListener('click', () => {
|
||||||
|
showModal(el.dataset.name, el.dataset.prefix);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
relatedSection.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
modalOverlay.classList.add('show');
|
modalOverlay.classList.add('show');
|
||||||
animateModal();
|
animateModal();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user