mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
Make icons searchable!
This commit is contained in:
@@ -2,30 +2,18 @@
|
||||
|
||||
[component-header:sl-icon]
|
||||
|
||||
Icons...
|
||||
Icons are symbols that can be used to represent or provide context to various options and actions within an application.
|
||||
|
||||
The icons that come bundled with Shoelace are courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project.
|
||||
Shoelace comes bundled with over 600 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. However, you can also use your own SVG icons with the `src` attribute.
|
||||
|
||||
```html preview
|
||||
<sl-icon name="exclamation-triangle"></sl-icon>
|
||||
<sl-icon name="archive"></sl-icon>
|
||||
<sl-icon name="battery-charging"></sl-icon>
|
||||
<sl-icon name="bell"></sl-icon>
|
||||
<sl-icon name="clock"></sl-icon>
|
||||
<sl-icon name="download"></sl-icon>
|
||||
<sl-icon name="file-earmark"></sl-icon>
|
||||
<sl-icon name="flag"></sl-icon>
|
||||
<sl-icon name="heart"></sl-icon>
|
||||
<sl-icon name="image"></sl-icon>
|
||||
<sl-icon name="lightning"></sl-icon>
|
||||
<sl-icon name="mic"></sl-icon>
|
||||
<sl-icon name="search"></sl-icon>
|
||||
<sl-icon name="star"></sl-icon>
|
||||
<sl-icon name="trash"></sl-icon>
|
||||
<sl-icon name="x-circle"></sl-icon>
|
||||
```
|
||||
Hover to see the respective icon's `name` or click to copy the HTML tag to the clipboard.
|
||||
|
||||
?> For a searchable list of 600+ icons, please refer to the [Bootstrap Icons website](https://icons.getbootstrap.com/).
|
||||
<div class="icon-search">
|
||||
<sl-input placeholder="Search Icons" clearable class="icon-search"></sl-input>
|
||||
<div class="icon-loader"><sl-spinner size="48"></sl-spinner></div>
|
||||
<div class="icon-list" hidden></div>
|
||||
<input type="text" class="icon-copy-input">
|
||||
</div>
|
||||
|
||||
[component-metadata:sl-icon]
|
||||
|
||||
@@ -54,4 +42,99 @@ Icon sizes are determined by the current font size.
|
||||
<sl-icon name="trash"></sl-icon>
|
||||
<sl-icon name="x-circle"></sl-icon>
|
||||
</div>
|
||||
```
|
||||
```
|
||||
|
||||
<script>
|
||||
fetch('/dist/shoelace/icons/icons.json')
|
||||
.then(res => res.json())
|
||||
.then(icons => {
|
||||
const container = document.querySelector('.icon-search');
|
||||
const input = container.querySelector('sl-input');
|
||||
const copyInput = container.querySelector('.icon-copy-input');
|
||||
const loader = container.querySelector('.icon-loader');
|
||||
const list = container.querySelector('.icon-list');
|
||||
const queue = [];
|
||||
|
||||
icons.map(i => {
|
||||
const icon = document.createElement('sl-icon');
|
||||
icon.setAttribute('data-name', i.name);
|
||||
icon.setAttribute('data-terms', [...i.tags || [], i.categories || [], i.title].join(' '));
|
||||
icon.name = i.name;
|
||||
|
||||
const tooltip = document.createElement('sl-tooltip');
|
||||
tooltip.content = i.name;
|
||||
|
||||
tooltip.appendChild(icon);
|
||||
list.appendChild(tooltip);
|
||||
|
||||
queue.push(new Promise((resolve, reject) => {
|
||||
icon.addEventListener('slLoad', () => resolve());
|
||||
icon.addEventListener('slError', () => reoslve());
|
||||
}));
|
||||
|
||||
icon.addEventListener('click', () => {
|
||||
copyInput.value = `<sl-icon name="${i.name}"></sl-icon>`;
|
||||
copyInput.select();
|
||||
document.execCommand('copy');
|
||||
tooltip.content = 'Copied!';
|
||||
setTimeout(() => tooltip.content = i.name, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
Promise.all(queue).then(() => {
|
||||
list.hidden = false;
|
||||
loader.hidden = true;
|
||||
});
|
||||
|
||||
input.addEventListener('slInput', () => {
|
||||
[...list.querySelectorAll('sl-icon')].map(slIcon => {
|
||||
if (input.value === '') {
|
||||
slIcon.hidden = false;
|
||||
} else {
|
||||
const terms = slIcon.getAttribute('data-terms').toLowerCase();
|
||||
const filter = input.value.toLowerCase();
|
||||
slIcon.hidden = terms.indexOf(filter) < 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-loader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 30vh;
|
||||
}
|
||||
|
||||
.icon-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.icon-loader[hidden],
|
||||
.icon-list[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.icon-list sl-icon {
|
||||
font-size: 32px;
|
||||
border-radius: var(--sl-border-radius-medium);
|
||||
padding: .5em;
|
||||
transition: var(--sl-transition-medium) all;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon-list sl-icon:hover {
|
||||
background-color: var(--sl-color-primary-95);
|
||||
color: var(--sl-color-primary-50);
|
||||
}
|
||||
|
||||
.icon-copy-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
61
make-icons.js
Normal file
61
make-icons.js
Normal file
@@ -0,0 +1,61 @@
|
||||
const Promise = require('bluebird');
|
||||
const promisify = require('util').promisify;
|
||||
const chalk = require('chalk');
|
||||
const copy = require('recursive-copy');
|
||||
const del = require('del');
|
||||
const download = require('download');
|
||||
const fm = require('front-matter');
|
||||
const fs = require('fs').promises;
|
||||
const glob = promisify(require('glob'));
|
||||
const latestVersion = require('latest-version');
|
||||
const path = require('path');
|
||||
|
||||
let numIcons = 0;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
// Determine the latest version of Bootstrap icons
|
||||
const version = await latestVersion('bootstrap-icons');
|
||||
const srcPath = `./temp/icons-${version}`;
|
||||
const url = `https://github.com/twbs/icons/archive/v${version}.zip`;
|
||||
|
||||
// Download the source from GitHub (since not everything is published to NPM)
|
||||
console.log(chalk.cyan(`\nDownloading and extracting ${version}... 📦\n`));
|
||||
await del(['./src/components/icon/icons', './temp']);
|
||||
await download(url, './temp', { extract: true });
|
||||
|
||||
// Copy icons
|
||||
console.log(chalk.cyan(`Copying icons and license... 🚛\n`));
|
||||
await Promise.all([
|
||||
copy(`${srcPath}/icons`, './src/components/icon/icons'),
|
||||
copy(`${srcPath}/LICENSE.md`, './src/components/icon/icons/LICENSE.md')
|
||||
]);
|
||||
|
||||
// Generate metadata
|
||||
console.log(chalk.cyan(`Generating icon metadata... 🏷\n`));
|
||||
const files = await glob(`${srcPath}/docs/content/icons/**/*.md`);
|
||||
|
||||
const metadata = await Promise.map(files, async file => {
|
||||
const name = path.basename(file, path.extname(file));
|
||||
const data = fm(await fs.readFile(file, 'utf8')).attributes;
|
||||
numIcons++;
|
||||
|
||||
return {
|
||||
name,
|
||||
title: data.title,
|
||||
categories: data.categories,
|
||||
tags: data.tags
|
||||
};
|
||||
});
|
||||
|
||||
await fs.writeFile('./src/components/icon/icons/icons.json', JSON.stringify(metadata, null, 2), 'utf8');
|
||||
|
||||
// More cleanup
|
||||
console.log(chalk.cyan(`Cleaning up... 🧹\n`));
|
||||
await del('./temp');
|
||||
|
||||
console.log(chalk.green(`Successfully processed ${numIcons} icons! ✨\n`));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
1074
package-lock.json
generated
1074
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -24,25 +24,30 @@
|
||||
"generate": "stencil generate",
|
||||
"serve": "node dev-server.js",
|
||||
"prebuild": "npm run lint",
|
||||
"postbuild": "node postbuild.js",
|
||||
"postinstall": "node postinstall.js",
|
||||
"postbuild": "node make-dist.js",
|
||||
"postinstall": "node make-icons.js",
|
||||
"version": "npm run build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stencil/eslint-plugin": "^0.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^2.28.0",
|
||||
"@typescript-eslint/parser": "^2.28.0",
|
||||
"bluebird": "^3.7.2",
|
||||
"bootstrap-icons": "^1.0.0-alpha4",
|
||||
"browser-sync": "^2.26.7",
|
||||
"chalk": "^4.0.0",
|
||||
"concurrently": "^5.1.0",
|
||||
"del": "^5.1.0",
|
||||
"download": "^8.0.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"express": "^4.17.1",
|
||||
"front-matter": "^4.0.2",
|
||||
"glob": "^7.1.6",
|
||||
"http-proxy": "^1.18.1",
|
||||
"http-proxy-middleware": "^1.0.4",
|
||||
"husky": "^4.2.5",
|
||||
"latest-version": "^5.1.0",
|
||||
"recursive-copy": "^2.0.10",
|
||||
"through2": "^3.0.1",
|
||||
"workbox-build": "4.3.1"
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
const chalk = require('chalk');
|
||||
const copy = require('recursive-copy');
|
||||
const del = require('del');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
// Copy Bootstrap Icons to src/components/icon/icons since local assets can't be linked from node_modules
|
||||
console.log(chalk.cyan('Copying icons 📦\n'));
|
||||
|
||||
await del('./src/components/icon/icons');
|
||||
await copy('./node_modules/bootstrap-icons/icons', './src/components/icon/icons');
|
||||
await copy('./node_modules/bootstrap-icons/LICENSE.md', './src/components/icon/icons/LICENSE.md');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user