Skip to content

Commit 4c23d6c

Browse files
joeVennerclaude
andcommitted
feat(ui): replace emoji icons with SVG icon system
Replace all emoji icons with a consistent SVG icon system to improve: - Visual consistency across platforms - Design token control and theming - Professional appearance Changes: - Add new Icon.astro component with 16 custom SVG icons - Update index.astro to use SVG icons in resource cards - Update index.ts to render SVG icons in search results - Update utils.ts to return icon names instead of emojis - Update global.css with proper SVG icon styling - Remove emoji from Footer component Icons added: robot, document, lightning, hook, workflow, plug, wrench, book, plus action icons: close, copy, download, share, external, plus, search, chevron-down Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ccabb66 commit 4c23d6c

6 files changed

Lines changed: 145 additions & 24 deletions

File tree

website/src/components/Footer.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { Icon } from "@astrojs/starlight/components";
2121
)
2222
}
2323

24-
<p class="made-by">Made with ❤️ by our amazing <a href="/contributors/">contributors</a></p>
24+
<p class="made-by">Made with love by our amazing <a href="/contributors/">contributors</a></p>
2525
</footer>
2626

2727
<style>

website/src/components/Icon.astro

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
// Icon component with SVG icons to replace emojis
3+
// Using consistent stroke width and style for all icons
4+
5+
export interface Props {
6+
name: 'agents' | 'instructions' | 'skills' | 'hooks' | 'workflows' | 'plugins' | 'tools' | 'learning' | 'close' | 'copy' | 'download' | 'share' | 'external' | 'plus' | 'search' | 'chevron-down' | 'document' | 'lightning' | 'hook' | 'workflow' | 'plug' | 'wrench' | 'book' | 'robot';
7+
size?: number;
8+
class?: string;
9+
}
10+
11+
const { name, size = 24, class: className = '' } = Astro.props;
12+
13+
// SVG icon paths - consistent 1.5px stroke width, rounded caps
14+
const icons: Record<string, string> = {
15+
// Resource type icons
16+
'robot': `<path d="M9 15.5h6M12 12v3.5M12 6.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 10.5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-7Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M4.5 12.5h-2a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h2M19.5 12.5h2a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
17+
18+
'document': `<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
19+
20+
'lightning': `<path d="M13 2 4.09 12.11a1.23 1.23 0 0 0 .13 1.72l.16.14a1.23 1.23 0 0 0 1.52 0L13 9.5V22l8.91-10.11a1.23 1.23 0 0 0-.13-1.72l-.16-.14a1.23 1.23 0 0 0-1.52 0L13 14.5V2Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
21+
22+
'hook': `<path d="M12 22a5 5 0 0 0 5-5c0-2.5-2-3.5-4-5.5s-3-4-3-6.5a5 5 0 0 1 10 0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 22a5 5 0 0 1-5-5c0-2.5 2-3.5 4-5.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
23+
24+
'workflow': `<path d="M4 7h16M4 17h16M8 3v4M8 13v4M16 3v4M16 13v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="8" cy="7" r="2" stroke="currentColor" stroke-width="1.5"/><circle cx="16" cy="7" r="2" stroke="currentColor" stroke-width="1.5"/><circle cx="8" cy="17" r="2" stroke="currentColor" stroke-width="1.5"/><circle cx="16" cy="17" r="2" stroke="currentColor" stroke-width="1.5"/>`,
25+
26+
'plug': `<path d="M12 22v-5M8 17h8M6 2v8a4 4 0 0 0 4 4h4a4 4 0 0 0 4-4V2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M6 2h4M14 2h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
27+
28+
'wrench': `<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
29+
30+
'book': `<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
31+
32+
// Action icons
33+
'close': `<path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
34+
35+
'copy': `<path d="M8 4h8a2 2 0 0 1 2 2v8M8 4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 4v10a2 2 0 0 0 2 2h8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
36+
37+
'download': `<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
38+
39+
'share': `<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8M16 6l-4-4-4 4M12 2v13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
40+
41+
'external': `<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14 21 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
42+
43+
'plus': `<path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
44+
45+
'search': `<circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="m21 21-4.35-4.35" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
46+
47+
'chevron-down': `<path d="m6 9 6 6 6-6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`,
48+
};
49+
50+
const iconPath = icons[name] || '';
51+
---
52+
53+
<svg
54+
viewBox="0 0 24 24"
55+
width={size}
56+
height={size}
57+
fill="none"
58+
class={className}
59+
aria-hidden="true"
60+
set:html={iconPath}
61+
/>

website/src/pages/index.astro

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
33
import Modal from '../components/Modal.astro';
4+
import Icon from '../components/Icon.astro';
45
56
const base = import.meta.env.BASE_URL;
67
---
@@ -57,63 +58,71 @@ const base = import.meta.env.BASE_URL;
5758
<div class="container">
5859
<div class="cards-grid">
5960
<a href={`${base}agents/`} class="card card-with-count" id="card-agents">
60-
<div class="card-icon" aria-hidden="true">🤖</div>
61+
<div class="card-icon" aria-hidden="true"><Icon name="robot" size={40} /></div>
6162
<div class="card-content">
6263
<h3>Agents</h3>
6364
<p>Custom agents for specialized Copilot experiences</p>
6465
</div>
6566
<div class="card-count" data-count="agents" aria-label="Agent count">-</div>
6667
</a>
6768
<a href={`${base}instructions/`} class="card card-with-count" id="card-instructions">
68-
<div class="card-icon" aria-hidden="true">📋</div>
69+
<div class="card-icon" aria-hidden="true"><Icon name="document" size={40} /></div>
6970
<div class="card-content">
7071
<h3>Instructions</h3>
7172
<p>Coding standards and best practices for Copilot</p>
7273
</div>
7374
<div class="card-count" data-count="instructions" aria-label="Instruction count">-</div>
7475
</a>
7576
<a href={`${base}skills/`} class="card card-with-count" id="card-skills">
76-
<div class="card-icon" aria-hidden="true"></div>
77+
<div class="card-icon" aria-hidden="true"><Icon name="lightning" size={40} /></div>
7778
<div class="card-content">
7879
<h3>Skills</h3>
7980
<p>Self-contained folders with instructions and resources</p>
8081
</div>
8182
<div class="card-count" data-count="skills" aria-label="Skill count">-</div>
8283
</a>
8384
<a href={`${base}hooks/`} class="card card-with-count" id="card-hooks">
84-
<div class="card-icon" aria-hidden="true">🪝</div>
85+
<div class="card-icon" aria-hidden="true"><Icon name="hook" size={40} /></div>
8586
<div class="card-content">
8687
<h3>Hooks</h3>
8788
<p>Automated workflows triggered by agent events</p>
8889
</div>
8990
<div class="card-count" data-count="hooks" aria-label="Hook count">-</div>
9091
</a>
9192
<a href={`${base}workflows/`} class="card card-with-count" id="card-workflows">
92-
<div class="card-icon" aria-hidden="true">⚡</div>
93+
<div class="card-icon" aria-hidden="true">
94+
<Icon name="workflow" size={40} />
95+
</div>
9396
<div class="card-content">
9497
<h3>Workflows</h3>
9598
<p>AI-powered automations for GitHub Actions</p>
9699
</div>
97100
<div class="card-count" data-count="workflows" aria-label="Workflow count">-</div>
98101
</a>
99102
<a href={`${base}plugins/`} class="card card-with-count" id="card-plugins">
100-
<div class="card-icon" aria-hidden="true">🔌</div>
103+
<div class="card-icon" aria-hidden="true">
104+
<Icon name="plug" size={40} />
105+
</div>
101106
<div class="card-content">
102107
<h3>Plugins</h3>
103108
<p>Curated plugins organized by themes</p>
104109
</div>
105110
<div class="card-count" data-count="plugins" aria-label="Plugin count">-</div>
106111
</a>
107112
<a href={`${base}tools/`} class="card card-with-count" id="card-tools">
108-
<div class="card-icon" aria-hidden="true">🔧</div>
113+
<div class="card-icon" aria-hidden="true">
114+
<Icon name="wrench" size={40} />
115+
</div>
109116
<div class="card-content">
110117
<h3>Tools</h3>
111118
<p>MCP servers and developer tools</p>
112119
</div>
113120
<div class="card-count" data-count="tools" aria-label="Tool count">-</div>
114121
</a>
115122
<a href={`${base}learning-hub/`} class="card card-with-count" id="card-learning-hub">
116-
<div class="card-icon" aria-hidden="true">📚</div>
123+
<div class="card-icon" aria-hidden="true">
124+
<Icon name="book" size={40} />
125+
</div>
117126
<div class="card-content">
118127
<h3>Learning Hub</h3>
119128
<p>Articles and guides to master GitHub Copilot</p>

website/src/scripts/pages/index.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@ import { FuzzySearch, type SearchItem } from '../search';
55
import { fetchData, debounce, escapeHtml, truncate, getResourceIcon } from '../utils';
66
import { setupModal, openFileModal } from '../modal';
77

8+
// SVG icon paths for search results
9+
const iconPaths: Record<string, string> = {
10+
robot: '<path d="M9 15.5h6M12 12v3.5M12 6.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M4 10.5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-7Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M4.5 12.5h-2a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h2M19.5 12.5h2a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>',
11+
document: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>',
12+
lightning: '<path d="M13 2 4.09 12.11a1.23 1.23 0 0 0 .13 1.72l.16.14a1.23 1.23 0 0 0 1.52 0L13 9.5V22l8.91-10.11a1.23 1.23 0 0 0-.13-1.72l-.16-.14a1.23 1.23 0 0 0-1.52 0L13 14.5V2Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>',
13+
hook: '<path d="M12 22a5 5 0 0 0 5-5c0-2.5-2-3.5-4-5.5s-3-4-3-6.5a5 5 0 0 1 10 0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 22a5 5 0 0 1-5-5c0-2.5 2-3.5 4-5.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>',
14+
workflow: '<path d="M4 7h16M4 17h16M8 3v4M8 13v4M16 3v4M16 13v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><circle cx="8" cy="7" r="2" stroke="currentColor" stroke-width="1.5"/><circle cx="16" cy="7" r="2" stroke="currentColor" stroke-width="1.5"/><circle cx="8" cy="17" r="2" stroke="currentColor" stroke-width="1.5"/><circle cx="16" cy="17" r="2" stroke="currentColor" stroke-width="1.5"/>',
15+
plug: '<path d="M12 22v-5M8 17h8M6 2v8a4 4 0 0 0 4 4h4a4 4 0 0 0 4-4V2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M6 2h4M14 2h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>',
16+
wrench: '<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>',
17+
};
18+
19+
function getIconSvg(iconName: string): string {
20+
const path = iconPaths[iconName] || iconPaths.document;
21+
return `<svg viewBox="0 0 24 24" fill="none" aria-hidden="true">${path}</svg>`;
22+
}
23+
824
interface Manifest {
925
counts: {
1026
agents: number;
@@ -97,15 +113,17 @@ export async function initHomepage(): Promise<void> {
97113
statusEl.textContent = 'No results found.';
98114
}
99115
} else {
100-
resultsDiv.innerHTML = results.map(item => `
116+
resultsDiv.innerHTML = results.map(item => {
117+
const iconName = getResourceIcon(item.type);
118+
return `
101119
<button type="button" class="search-result" data-path="${escapeHtml(item.path)}" data-type="${escapeHtml(item.type)}">
102-
<span class="search-result-type">${getResourceIcon(item.type)}</span>
120+
<span class="search-result-type" data-icon="${iconName}">${getIconSvg(iconName)}</span>
103121
<div>
104122
<div class="search-result-title">${search.highlight(item.title, query)}</div>
105123
<div class="search-result-description">${truncate(item.description, 60)}</div>
106124
</div>
107125
</button>
108-
`).join('');
126+
`}).join('');
109127

110128
if (statusEl) {
111129
statusEl.textContent = `${results.length} result${results.length === 1 ? '' : 's'} available.`;

website/src/scripts/utils.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -344,18 +344,27 @@ export function formatResourceType(type: string): string {
344344
}
345345

346346
/**
347-
* Get icon for resource type
347+
* Get icon for resource type (returns SVG icon name)
348348
*/
349349
export function getResourceIcon(type: string): string {
350350
const icons: Record<string, string> = {
351-
agent: "🤖",
352-
instruction: "📋",
353-
skill: "",
354-
hook: "🪝",
355-
workflow: "",
356-
plugin: "🔌",
351+
agent: "robot",
352+
instruction: "document",
353+
skill: "lightning",
354+
hook: "hook",
355+
workflow: "workflow",
356+
plugin: "plug",
357357
};
358-
return icons[type] || "📄";
358+
return icons[type] || "document";
359+
}
360+
361+
/**
362+
* Get SVG icon HTML for resource type
363+
*/
364+
export function getResourceIconSvg(type: string, size = 20): string {
365+
const iconName = getResourceIcon(type);
366+
// Return a placeholder span that will be replaced with actual SVG
367+
return `<span class="resource-icon resource-icon--${iconName}" data-icon="${iconName}" data-size="${size}"></span>`;
359368
}
360369

361370
/**

website/src/styles/global.css

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,6 @@ body:has(#main-content) {
304304
}
305305

306306
.search-result-type {
307-
font-size: 20px;
308307
flex-shrink: 0;
309308
width: 36px;
310309
height: 36px;
@@ -313,8 +312,23 @@ body:has(#main-content) {
313312
justify-content: center;
314313
background: var(--color-bg-tertiary);
315314
border-radius: var(--border-radius);
315+
color: var(--color-primary);
316+
}
317+
318+
.search-result-type svg {
319+
width: 20px;
320+
height: 20px;
316321
}
317322

323+
/* Icon color variations by type */
324+
.search-result-type[data-icon="robot"] { color: #B870FF; }
325+
.search-result-type[data-icon="document"] { color: #F4A876; }
326+
.search-result-type[data-icon="lightning"] { color: #FE4C25; }
327+
.search-result-type[data-icon="hook"] { color: #C898FD; }
328+
.search-result-type[data-icon="workflow"] { color: #F08A3A; }
329+
.search-result-type[data-icon="plug"] { color: #10b981; }
330+
.search-result-type[data-icon="wrench"] { color: #60a5fa; }
331+
318332
.search-result-title {
319333
font-weight: 600;
320334
font-size: 15px;
@@ -417,14 +431,24 @@ body:has(#main-content) {
417431
}
418432

419433
.card-icon {
420-
font-size: 40px;
434+
width: 48px;
435+
height: 48px;
436+
display: flex;
437+
align-items: center;
438+
justify-content: center;
421439
margin-bottom: 16px;
422-
display: inline-block;
423-
transition: transform var(--transition);
440+
color: var(--color-primary);
441+
transition: transform var(--transition), color var(--transition);
442+
}
443+
444+
.card-icon svg {
445+
width: 100%;
446+
height: 100%;
424447
}
425448

426449
.card:hover .card-icon {
427450
transform: scale(1.1);
451+
color: var(--color-accent-hover);
428452
}
429453

430454
.card h3 {

0 commit comments

Comments
 (0)