committed by
GitHub
20 changed files with 608 additions and 1429 deletions
@ -1,56 +0,0 @@ |
|||
const sass = require("sass"); |
|||
const path = require("path"); |
|||
|
|||
module.exports = function (eleventyConfig) { |
|||
eleventyConfig.addTemplateFormats("scss"); |
|||
|
|||
eleventyConfig.addExtension("scss", { |
|||
outputFileExtension: "css", |
|||
compile: async function(inputContent, inputPath) { |
|||
const parsed = path.parse(inputPath); |
|||
if (parsed.name.startsWith("_")) { |
|||
return; |
|||
} |
|||
|
|||
const result = sass.compileString(inputContent, { |
|||
loadPaths: [parsed.dir || ".", path.join(process.cwd(), "src", "_includes")], |
|||
style: "expanded" |
|||
}); |
|||
|
|||
return async (data) => { |
|||
return result.css; |
|||
}; |
|||
} |
|||
}); |
|||
|
|||
eleventyConfig.addWatchTarget("./src"); |
|||
eleventyConfig.addWatchTarget("./icons"); |
|||
|
|||
eleventyConfig.setQuietMode(true); |
|||
|
|||
eleventyConfig.addLiquidTag("include_cached", function (liquidEngine) { |
|||
return { |
|||
parse: function (tagToken, remainingTokens) { |
|||
this.str = tagToken.args; |
|||
}, |
|||
render: async function (scope, hash) { |
|||
var str = await this.liquid.evalValue(this.str, scope); |
|||
return str; |
|||
} |
|||
}; |
|||
}); |
|||
|
|||
eleventyConfig.addFilter("group_by", function (value) { |
|||
return value |
|||
}); |
|||
|
|||
return { |
|||
pathPrefix: "/", |
|||
dir: { |
|||
input: "src", |
|||
layouts: "_layouts", |
|||
includes: "_includes" |
|||
}, |
|||
}; |
|||
}; |
|||
|
|||
@ -0,0 +1,59 @@ |
|||
import path from 'node:path'; |
|||
import { defineConfig } from 'astro/config'; |
|||
|
|||
const root = process.cwd(); |
|||
const iconsDir = path.join(root, 'icons'); |
|||
|
|||
// The icon loaders read `icons/` straight from disk, so Vite has no import
|
|||
// edge to follow and would keep serving a stale module after an icon changes.
|
|||
// Watch the directory ourselves and drop the loaders from the SSR graph.
|
|||
const dataModules = [ |
|||
path.join(root, 'src', 'data', 'icons.js'), |
|||
path.join(root, 'src', 'data', 'grouped-icons.js'), |
|||
]; |
|||
|
|||
function watchIcons() { |
|||
return { |
|||
name: 'tabler:watch-icons', |
|||
apply: 'serve', |
|||
configureServer(server) { |
|||
server.watcher.add(iconsDir); |
|||
|
|||
const graphs = [server.environments?.ssr?.moduleGraph, server.moduleGraph].filter(Boolean); |
|||
|
|||
const reload = (file) => { |
|||
if (!file.startsWith(iconsDir + path.sep) || !file.endsWith('.svg')) return; |
|||
|
|||
for (const graph of graphs) { |
|||
for (const id of dataModules) { |
|||
const mod = graph.getModuleById(id); |
|||
if (mod) graph.invalidateModule(mod); |
|||
} |
|||
} |
|||
|
|||
(server.hot ?? server.ws).send({ type: 'full-reload' }); |
|||
}; |
|||
|
|||
server.watcher.on('add', reload); |
|||
server.watcher.on('change', reload); |
|||
server.watcher.on('unlink', reload); |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
// Internal preview site for browsing the icon set. Output stays in `_site`
|
|||
// so the existing `pnpm run preview` link in the release chain keeps working.
|
|||
export default defineConfig({ |
|||
outDir: './_site', |
|||
build: { |
|||
assets: '_assets', |
|||
// Keep the stylesheet as its own file instead of inlining it into every page.
|
|||
inlineStylesheets: 'never', |
|||
}, |
|||
devToolbar: { |
|||
enabled: false, |
|||
}, |
|||
vite: { |
|||
plugins: [watchIcons()], |
|||
}, |
|||
}); |
|||
File diff suppressed because it is too large
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -1,44 +0,0 @@ |
|||
const matter = require('gray-matter'); |
|||
const path = require('path'); |
|||
const { globSync } = require('glob'); |
|||
|
|||
module.exports = (function () { |
|||
const outlineIcons = globSync(path.join(__dirname, '../../icons', `outline/*.svg`)).sort((a, b) => path.basename(a).localeCompare(path.basename(b))) |
|||
const filledIcons = globSync(path.join(__dirname, '../../icons', `filled/*.svg`)).sort((a, b) => path.basename(a).localeCompare(path.basename(b))) |
|||
|
|||
const icons = {}; |
|||
outlineIcons.forEach(icon => { |
|||
const name = path.basename(icon, ".svg"), |
|||
{ data, content } = matter.read(icon, { delims: ['<!--', '-->'] }) |
|||
|
|||
icons[name] = { |
|||
name: name, |
|||
data: { |
|||
category: data.category || '', |
|||
tags: data.tags || [], |
|||
}, |
|||
styles: { |
|||
outline: { |
|||
version: data.version || '', |
|||
unicode: data.unicode || '', |
|||
content: content.replace(/(<svg[^>]+>)/, `$1\n <path stroke="none" d="M0 0h24v24H0z" fill="none"/>`) |
|||
} |
|||
} |
|||
} |
|||
}) |
|||
|
|||
filledIcons.forEach(icon => { |
|||
const name = path.basename(icon, ".svg"), |
|||
{ data, content } = matter.read(icon, { delims: ['<!--', '-->'] }) |
|||
|
|||
if (icons[name]) { |
|||
icons[name].styles.filled = { |
|||
version: data.version || '', |
|||
unicode: data.unicode || '', |
|||
content: content.replace(/(<svg[^>]+>)/, `$1\n <path stroke="none" d="M0 0h24v24H0z" fill="none"/>`) |
|||
} |
|||
} |
|||
}) |
|||
|
|||
return Object.values(icons); |
|||
})(); |
|||
@ -1,30 +0,0 @@ |
|||
const matter = require('gray-matter'); |
|||
const path = require('path'); |
|||
const { globSync } = require('glob'); |
|||
|
|||
module.exports = (function () { |
|||
const types = ['outline', 'filled'] |
|||
|
|||
return types.map(type => { |
|||
const p = path.join(__dirname, `../../icons/${type}/*.svg`); |
|||
|
|||
const icons = globSync(p).map((icon) => { |
|||
const { data, content } = matter.read(icon, { delims: ['<!--', '-->'] }) |
|||
|
|||
return { |
|||
name: path.basename(icon, ".svg"), |
|||
data, |
|||
content |
|||
} |
|||
}).sort((a, b) => { |
|||
return a.name.localeCompare(b.name); |
|||
}); |
|||
|
|||
console.log(`Found ${icons.length} ${type} icons`); |
|||
|
|||
return { |
|||
type, |
|||
icons |
|||
} |
|||
}) |
|||
})(); |
|||
@ -1,3 +0,0 @@ |
|||
module.exports = (function () { |
|||
return process.env.ELEVENTY_RUN_MODE === "build"; |
|||
})(); |
|||
@ -1,32 +0,0 @@ |
|||
--- |
|||
--- |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" |
|||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
|
|||
<link rel="stylesheet" href="{{ site.baseurl }}/style.css"> |
|||
<title>{% if not production %}DEV - {% endif %}Tabler Icons</title> |
|||
|
|||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script> |
|||
<style> |
|||
body { |
|||
display: none; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
|
|||
{{ content }} |
|||
|
|||
<script> |
|||
$(document).ready(function(){ |
|||
document.body.style.display = "block"; |
|||
}); |
|||
</script> |
|||
|
|||
</body> |
|||
</html> |
|||
@ -1,32 +0,0 @@ |
|||
--- |
|||
--- |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" |
|||
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> |
|||
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|||
|
|||
<link rel="stylesheet" href="{{ site.baseurl }}/style.css"> |
|||
<title>{% if not production %}DEV - {% endif %}Tabler Icons</title> |
|||
|
|||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script> |
|||
<style> |
|||
body { |
|||
display: none; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
|
|||
{{ content }} |
|||
|
|||
<script> |
|||
$(document).ready(function(){ |
|||
document.body.style.display = "block"; |
|||
}); |
|||
</script> |
|||
|
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,57 @@ |
|||
import path from 'node:path'; |
|||
import matter from 'gray-matter'; |
|||
import { globSync } from 'glob'; |
|||
|
|||
// Astro runs with the project root as cwd; the icon set lives at <root>/icons.
|
|||
const iconsDir = path.join(process.cwd(), 'icons'); |
|||
|
|||
export const groupedIcons = (function () { |
|||
const outlineIcons = globSync(path.join(iconsDir, 'outline', '*.svg')).sort((a, b) => |
|||
path.basename(a).localeCompare(path.basename(b)) |
|||
); |
|||
const filledIcons = globSync(path.join(iconsDir, 'filled', '*.svg')).sort((a, b) => |
|||
path.basename(a).localeCompare(path.basename(b)) |
|||
); |
|||
|
|||
const icons = {}; |
|||
outlineIcons.forEach((icon) => { |
|||
const name = path.basename(icon, '.svg'), |
|||
{ data, content } = matter.read(icon, { delims: ['<!--', '-->'] }); |
|||
|
|||
icons[name] = { |
|||
name: name, |
|||
data: { |
|||
category: data.category || '', |
|||
tags: data.tags || [], |
|||
}, |
|||
styles: { |
|||
outline: { |
|||
version: data.version || '', |
|||
unicode: data.unicode || '', |
|||
content: content.replace( |
|||
/(<svg[^>]+>)/, |
|||
`$1\n <path stroke="none" d="M0 0h24v24H0z" fill="none"/>` |
|||
), |
|||
}, |
|||
}, |
|||
}; |
|||
}); |
|||
|
|||
filledIcons.forEach((icon) => { |
|||
const name = path.basename(icon, '.svg'), |
|||
{ data, content } = matter.read(icon, { delims: ['<!--', '-->'] }); |
|||
|
|||
if (icons[name]) { |
|||
icons[name].styles.filled = { |
|||
version: data.version || '', |
|||
unicode: data.unicode || '', |
|||
content: content.replace( |
|||
/(<svg[^>]+>)/, |
|||
`$1\n <path stroke="none" d="M0 0h24v24H0z" fill="none"/>` |
|||
), |
|||
}; |
|||
} |
|||
}); |
|||
|
|||
return Object.values(icons); |
|||
})(); |
|||
@ -0,0 +1,35 @@ |
|||
import path from 'node:path'; |
|||
import matter from 'gray-matter'; |
|||
import { globSync } from 'glob'; |
|||
|
|||
// Astro runs with the project root as cwd; the icon set lives at <root>/icons.
|
|||
const iconsDir = path.join(process.cwd(), 'icons'); |
|||
|
|||
export const icons = (function () { |
|||
const types = ['outline', 'filled']; |
|||
|
|||
return types.map((type) => { |
|||
const p = path.join(iconsDir, type, '*.svg'); |
|||
|
|||
const icons = globSync(p) |
|||
.map((icon) => { |
|||
const { data, content } = matter.read(icon, { delims: ['<!--', '-->'] }); |
|||
|
|||
return { |
|||
name: path.basename(icon, '.svg'), |
|||
data, |
|||
content, |
|||
}; |
|||
}) |
|||
.sort((a, b) => { |
|||
return a.name.localeCompare(b.name); |
|||
}); |
|||
|
|||
console.log(`Found ${icons.length} ${type} icons`); |
|||
|
|||
return { |
|||
type, |
|||
icons, |
|||
}; |
|||
}); |
|||
})(); |
|||
@ -1,159 +0,0 @@ |
|||
--- |
|||
layout: default |
|||
--- |
|||
|
|||
<div class="container"> |
|||
<div class="box"> |
|||
|
|||
{% assign icons = site.icons %} |
|||
|
|||
{% comment %} |
|||
{% assign first-icon = site.icons | reverse | first %} |
|||
{% assign slug = first-icon.slug %} |
|||
{% capture first-icon %} |
|||
{% include icon.html name=slug %} |
|||
{% endcapture %} |
|||
|
|||
<div class="row mb js-icon-manager"> |
|||
<div class="col"> |
|||
|
|||
<div class="icon-preview-wrap"> |
|||
<div class="icon-preview"> |
|||
{{ first-icon }} |
|||
{{ first-icon }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-aside"> |
|||
|
|||
<h1 class="icon-title js-icon-name">{{ slug }}</h1> |
|||
|
|||
<div class="mb"> |
|||
<button class="btn"> |
|||
{{ first-icon }} Button |
|||
</button> |
|||
<button class="btn btn-icon"> |
|||
{{ first-icon }} |
|||
</button> |
|||
<button class="btn btn-link"> |
|||
{{ first-icon }} Button |
|||
</button> |
|||
</div> |
|||
|
|||
<div class="input-icon mb"> |
|||
<input type="text" class="input" value="Input value"> |
|||
{{ first-icon }} |
|||
</div> |
|||
|
|||
<div class="input-icon icon-left mb"> |
|||
{{ first-icon }} |
|||
<input type="text" class="input" placeholder="Input placeholder"> |
|||
</div> |
|||
|
|||
<div class="mb"> |
|||
<div class="avatar">{{ first-icon }}</div> |
|||
<div class="avatar avatar-sm">{{ first-icon }}</div> |
|||
|
|||
<a href="#">{{ first-icon }} Link</a> |
|||
</div> |
|||
|
|||
<div class="tabs mb"> |
|||
<a class="tab active">{{ first-icon }} Tab 1</a> |
|||
<a class="tab">Tab 2</a> |
|||
<a class="tab">Tab 3</a> |
|||
</div> |
|||
|
|||
<div class="mb"> |
|||
<textarea rows="10" class="input js-textarea"></textarea> |
|||
</div> |
|||
|
|||
|
|||
<div class="mt-auto"> |
|||
<input class="input-range js-input-range" type="range" min="1.25" max="2.75" step=".25" value="2"> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mb"> |
|||
{% include_cached toolbar.html toolbar='arrow-back-up,arrow-forward-up,printer,paint|bold,italic,underline,strikethrough,emphasis,baseline|align-left,align-center,align-right,align-justified,line-height|list,list-check,list-numbers|h-1,h-2,h-3,h-4,h-5,h-6,link,photo,table,regex|sort-ascending,sort-descending,sort-ascending-letters,sort-ascending-numbers|indent-increase,indent-decrease|subscript,superscript|minus,omega,chart-area-line,pencil|eraser,settings,typography,letters-case,clear-formatting|parentheses,brackets,braces,terminal|bike,run,swimming,walk,pray,fall,karate|heart,spade,diamonds,clubs|repeat,repeat-once,switch,player-record,player-play,player-pause,player-stop,power,player-skip-forward,player-skip-back,player-track-next,player-track-prev,player-eject' %} |
|||
</div> |
|||
|
|||
{% assign new-icons = icons | where: "version", null %} |
|||
|
|||
{% if new-icons %} |
|||
<h2 class="icon-subtitle">New icons ({{ new-icons | size }})</h2> |
|||
|
|||
<div class="mb"> |
|||
<div class="icons-list"> |
|||
{% for icon in new-icons %} |
|||
{% assign name = icon.slug %} |
|||
<a href="#" class="icons-list-icon js-icon" title="{{ icon.slug }}" data-icon="{{ name }}"{% unless icon.category %} style="color: #999" {% endunless %}> |
|||
{% include_cached icon.html name=name %} |
|||
</a> |
|||
{% endfor %} |
|||
</div> |
|||
</div> |
|||
{% endif %} |
|||
|
|||
<h2 class="icon-subtitle">{{ site.icons-outline.size | plus: site.icons-solid.size }} icons</h2> |
|||
|
|||
{% assign styles = "icons-outline,icons-solid" | split: "," %} |
|||
{% for style in styles %} |
|||
{% assign icons = site[style] | group_by: "category" %} |
|||
<div class="mb"> |
|||
{% for category in icons %} |
|||
{% if category.name %} |
|||
<h3 class="category-subtitle">{% if category.name != "" %}{{ category.name }}{% else %}Uncategorized{% endif %} <span class="text-muted">({{ category.items | size }})</span></h3> |
|||
{% endif %} |
|||
|
|||
<div class="icons-list"> |
|||
|
|||
{% for icon in category.items %} |
|||
{% assign name = icon.slug %} |
|||
<a href="#" class="icons-list-icon js-icon{% unless icon.version %} new-icon{% endunless %}" title="{{ icon.slug }}" data-icon="{{ name }}"> |
|||
{% include_cached icon.html name=name style=style %} |
|||
</a> |
|||
{% endfor %} |
|||
</div> |
|||
{% endfor %} |
|||
</div> |
|||
{% endfor %} |
|||
{% endcomment %} |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
$(document).ready(function () { |
|||
$('body') |
|||
.on('click', '.js-icon', function (e) { |
|||
var icon = $(this).attr('data-icon'); |
|||
|
|||
$('.js-icon').removeClass('active'); |
|||
$(this).addClass('active'); |
|||
|
|||
$('.js-icon-name').html(icon); |
|||
localStorage.setItem('icon', icon); |
|||
|
|||
$('.js-icon-manager svg').replaceWith($(this).find('>svg:eq(0)').clone()); |
|||
|
|||
$('.js-textarea').val($(this)[0].innerHTML.trim()); |
|||
|
|||
e.preventDefault(); |
|||
return false; |
|||
}) |
|||
.on('input', '.js-input-range', function (e) { |
|||
$('.js-icon svg').css('stroke-width', $(this).val()); |
|||
|
|||
e.preventDefault(); |
|||
return false; |
|||
}); |
|||
|
|||
|
|||
var icon = localStorage.getItem('icon'); |
|||
if (icon) { |
|||
$('.js-icon[data-icon="' + icon + '"]').eq(0).click(); |
|||
} |
|||
}); |
|||
</script> |
|||
@ -1,34 +0,0 @@ |
|||
--- |
|||
layout: default |
|||
--- |
|||
|
|||
<div class="container"> |
|||
<div class="box"> |
|||
<h3 class="box-title">new icons</h3> |
|||
{% for category in icons %} |
|||
{% for icon in category.icons %} |
|||
{% if not icon.data.version %} |
|||
<div class="icons-list-icon js-icon" title="{{ name }}"{% unless icon.data.category %} style="opacity: .66" {% endunless %}> |
|||
{{ icon.content }} |
|||
</div> |
|||
{% endif %} |
|||
{% endfor %} |
|||
{% endfor %} |
|||
</div> |
|||
|
|||
{% for category in icons %} |
|||
<div class="box"> |
|||
<div class="mb"> |
|||
<div class="icons-list"> |
|||
<h3 class="box-title">{{ category.type }}</h3> |
|||
{% for icon in category.icons %} |
|||
{% assign name = icon.name %} |
|||
<div class="icons-list-icon js-icon" title="{{ name }}"> |
|||
{{ icon.content }} |
|||
</div> |
|||
{% endfor %} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{% endfor %} |
|||
</div> |
|||
@ -0,0 +1,16 @@ |
|||
--- |
|||
import '../styles/style.scss'; |
|||
--- |
|||
|
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<link rel="icon" href="/favicon.ico" sizes="any" /> |
|||
<title>{import.meta.env.PROD ? '' : 'DEV - '}Tabler Icons</title> |
|||
</head> |
|||
<body> |
|||
<slot /> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,36 @@ |
|||
--- |
|||
import Layout from '../layouts/Layout.astro'; |
|||
import { icons } from '../data/icons.js'; |
|||
|
|||
// Thousands of icons land on this page, so the markup is assembled as a single |
|||
// string per box instead of thousands of Astro nodes. |
|||
const renderIcon = (icon) => { |
|||
const dimmed = icon.data.category ? '' : ' style="opacity: .66"'; |
|||
|
|||
return `<div class="icons-list-icon js-icon" title="${icon.name}"${dimmed}>${icon.content}</div>`; |
|||
}; |
|||
|
|||
const newIcons = icons.flatMap((category) => category.icons.filter((icon) => !icon.data.version)); |
|||
--- |
|||
|
|||
<Layout> |
|||
<div class="container"> |
|||
<div class="box"> |
|||
<h3 class="box-title">new icons</h3> |
|||
<Fragment set:html={newIcons.map(renderIcon).join('')} /> |
|||
</div> |
|||
|
|||
{ |
|||
icons.map((category) => ( |
|||
<div class="box"> |
|||
<div class="mb"> |
|||
<div class="icons-list"> |
|||
<h3 class="box-title">{category.type}</h3> |
|||
<Fragment set:html={category.icons.map(renderIcon).join('')} /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
)) |
|||
} |
|||
</div> |
|||
</Layout> |
|||
@ -0,0 +1,51 @@ |
|||
--- |
|||
import Layout from '../layouts/Layout.astro'; |
|||
import { groupedIcons } from '../data/grouped-icons.js'; |
|||
|
|||
const escape = (value) => |
|||
String(value ?? '') |
|||
.replace(/&/g, '&') |
|||
.replace(/</g, '<') |
|||
.replace(/>/g, '>'); |
|||
|
|||
// One row per icon, built as a single string — see index.astro for the rationale. |
|||
const rows = groupedIcons |
|||
.map( |
|||
(icon) => `<tr> |
|||
<td class="td-1"><a href="#" data-copy class="text-reset">${icon.styles.outline.content}</a></td> |
|||
<td class="td-1"><a href="#" data-copy class="text-reset">${icon.styles.filled?.content ?? ''}</a></td> |
|||
<th><a href="#" data-copy class="text-reset">${escape(icon.name)}</a></th> |
|||
<td>${escape(icon.data.tags.join(', '))}</td> |
|||
<td>${escape(icon.data.category)}</td> |
|||
<td>${escape(icon.styles.outline.version)}</td> |
|||
</tr>` |
|||
) |
|||
.join(''); |
|||
|
|||
const untagged = groupedIcons.filter((icon) => icon.data.tags.length === 0).length; |
|||
--- |
|||
|
|||
<Layout> |
|||
<div class="container"> |
|||
<div class="box"> |
|||
<table class="table mb"> |
|||
<tbody set:html={rows} /> |
|||
</table> |
|||
|
|||
<p>Untagged: {untagged}</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<script is:inline> |
|||
document.addEventListener('DOMContentLoaded', function () { |
|||
document.querySelectorAll('a[data-copy]').forEach(function (a) { |
|||
a.addEventListener('click', function (e) { |
|||
e.preventDefault(); |
|||
navigator.clipboard.writeText(this.innerHTML); |
|||
|
|||
return false; |
|||
}); |
|||
}); |
|||
}); |
|||
</script> |
|||
</Layout> |
|||
@ -1,503 +0,0 @@ |
|||
@use 'sass:color'; |
|||
|
|||
$breakpoint: 50rem; |
|||
$primary: #206bc4; |
|||
$border: #eeeeee; |
|||
$muted: #aaaaaa; |
|||
$dark: #354052; |
|||
$light: #fafbfc; |
|||
$btn-form-height: 2rem; |
|||
$hover: rgba(0, 0, 0, 0.04); |
|||
|
|||
* { |
|||
box-sizing: border-box; |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
html { |
|||
font-size: 16px; |
|||
font-family: |
|||
system-ui, |
|||
-apple-system, |
|||
BlinkMacSystemFont, |
|||
Segoe UI, |
|||
Roboto, |
|||
Helvetica Neue, |
|||
Arial, |
|||
Noto Sans, |
|||
sans-serif, |
|||
Apple Color Emoji, |
|||
Segoe UI Emoji, |
|||
Segoe UI Symbol, |
|||
Noto Color Emoji; |
|||
} |
|||
|
|||
body { |
|||
background: $light; |
|||
font-size: 0.9375rem; |
|||
color: $dark; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
|
|||
@media print { |
|||
color: #000; |
|||
} |
|||
} |
|||
|
|||
a { |
|||
color: $primary; |
|||
text-decoration: none; |
|||
|
|||
&:hover { |
|||
text-decoration: underline; |
|||
} |
|||
} |
|||
|
|||
.container { |
|||
max-width: 60rem; |
|||
margin: 0 auto; |
|||
padding: 1rem; |
|||
|
|||
@media (max-width: #{$breakpoint}) { |
|||
padding: 0; |
|||
} |
|||
|
|||
@media print { |
|||
padding: 0; |
|||
max-width: 100%; |
|||
} |
|||
} |
|||
|
|||
.row { |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
@media (min-width: #{$breakpoint}) { |
|||
flex-direction: row; |
|||
} |
|||
} |
|||
|
|||
.col { |
|||
flex: 1; |
|||
} |
|||
|
|||
.col-aside { |
|||
width: 15rem; |
|||
margin-top: 2rem; |
|||
display: flex; |
|||
flex-direction: column; |
|||
|
|||
@media (min-width: #{$breakpoint}) { |
|||
margin-top: 0; |
|||
margin-left: 2rem; |
|||
} |
|||
} |
|||
|
|||
.box { |
|||
padding: 2rem; |
|||
background: #ffff; |
|||
box-shadow: |
|||
0 0 0 1px rgba(0, 0, 0, 0.05), |
|||
0 1px 1px rgba(0, 0, 0, 0.1); |
|||
page-break-before: always; |
|||
margin-bottom: 2rem; |
|||
|
|||
@media (max-width: #{$breakpoint}) { |
|||
padding: 0.5rem; |
|||
box-shadow: none; |
|||
} |
|||
|
|||
@media print { |
|||
padding: 0; |
|||
box-shadow: none; |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
|
|||
.box-title { |
|||
font-size: 1.5rem; |
|||
line-height: 1; |
|||
margin: 0 0 1rem; |
|||
font-weight: 600; |
|||
|
|||
@media print { |
|||
display: none; |
|||
} |
|||
} |
|||
|
|||
.icon-title { |
|||
font-size: 1.25rem; |
|||
line-height: 1; |
|||
margin: 0 0 3rem; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.icon-subtitle { |
|||
font-size: 1rem; |
|||
line-height: 1; |
|||
margin: 0 0 1rem; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.category-subtitle { |
|||
font-size: 0.9rem; |
|||
line-height: 1; |
|||
margin: 1rem 0 0.5rem; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.icon-preview-wrap { |
|||
position: relative; |
|||
|
|||
&:before { |
|||
content: ''; |
|||
padding-top: 100%; |
|||
display: block; |
|||
} |
|||
} |
|||
|
|||
.icon-preview { |
|||
position: absolute; |
|||
width: 100%; |
|||
height: 100%; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background: url(bg.svg) no-repeat center/100%; |
|||
|
|||
svg { |
|||
width: 100%; |
|||
height: 100%; |
|||
opacity: 0.8; |
|||
|
|||
+ svg { |
|||
stroke-width: 0.08; |
|||
opacity: 1; |
|||
stroke: red; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
pointer-events: none; |
|||
|
|||
stroke-dasharray: 0 !important; |
|||
|
|||
* { |
|||
stroke-dasharray: 0 !important; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.icons-list { |
|||
display: table; |
|||
margin: -0.25rem; |
|||
} |
|||
|
|||
.icons-list-borders { |
|||
.icons-list-icon { |
|||
border-color: $dark; |
|||
} |
|||
} |
|||
|
|||
.icons-list-squares, |
|||
.icons-list-circles { |
|||
.icons-list-icon { |
|||
background: $dark; |
|||
color: $light; |
|||
} |
|||
} |
|||
|
|||
.icons-list-circles { |
|||
.icons-list-icon { |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
|
|||
.icons-list-icon { |
|||
margin: 0.25rem; |
|||
min-width: 2.25rem; |
|||
height: 2.25rem; |
|||
color: inherit; |
|||
border-radius: 3px; |
|||
display: inline-flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 1px solid transparent; |
|||
position: relative; |
|||
page-break-inside: avoid; |
|||
|
|||
&.new-icon { |
|||
&:after { |
|||
content: ''; |
|||
position: absolute; |
|||
top: 2px; |
|||
right: 2px; |
|||
width: 6px; |
|||
height: 6px; |
|||
background: #cc0000; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
|
|||
&.active { |
|||
background: #f0f0f0; |
|||
} |
|||
|
|||
@at-root a#{&}:hover { |
|||
opacity: 0.75; |
|||
} |
|||
|
|||
.icon { |
|||
display: block; |
|||
width: 1.5rem; |
|||
height: 1.5rem; |
|||
} |
|||
} |
|||
|
|||
.mb { |
|||
margin-bottom: 2rem; |
|||
} |
|||
|
|||
.mt-auto { |
|||
margin-top: auto; |
|||
} |
|||
|
|||
/* |
|||
Components |
|||
*/ |
|||
.btn { |
|||
display: inline-flex; |
|||
color: #ffffff; |
|||
background: $primary; |
|||
border: 0; |
|||
border-radius: 3px; |
|||
font-size: inherit; |
|||
line-height: 1; |
|||
justify-content: center; |
|||
align-items: center; |
|||
min-height: $btn-form-height; |
|||
min-width: $btn-form-height; |
|||
padding: 0 0.75rem; |
|||
|
|||
.icon { |
|||
width: 1rem; |
|||
height: 1rem; |
|||
margin: 0 0.5rem 0 -0.25rem; |
|||
} |
|||
} |
|||
|
|||
.btn-icon { |
|||
padding: 0; |
|||
justify-content: center; |
|||
|
|||
.icon { |
|||
margin: 0; |
|||
} |
|||
} |
|||
|
|||
.btn-link { |
|||
background: transparent; |
|||
color: $primary; |
|||
} |
|||
|
|||
.input { |
|||
border: 1px solid $border; |
|||
border-radius: 3px; |
|||
height: $btn-form-height; |
|||
display: block; |
|||
font-size: inherit; |
|||
font-family: inherit; |
|||
padding: 0 0.5rem; |
|||
width: 100%; |
|||
|
|||
&:focus { |
|||
outline: 0; |
|||
box-shadow: 0 0 0 3px rgba($primary, 0.1); |
|||
border-color: rgba($primary, 0.4); |
|||
} |
|||
|
|||
@at-root textarea#{&} { |
|||
min-height: 8rem; |
|||
} |
|||
} |
|||
|
|||
.icon { |
|||
width: 1em; |
|||
height: 1em; |
|||
vertical-align: -0.15em; |
|||
} |
|||
|
|||
.input-icon { |
|||
position: relative; |
|||
|
|||
.input { |
|||
padding-right: 2rem; |
|||
} |
|||
|
|||
.icon { |
|||
color: $muted; |
|||
width: 1.25rem; |
|||
height: 1.25rem; |
|||
position: absolute; |
|||
top: ($btn-form-height - 1.25rem) * 0.5; |
|||
right: ($btn-form-height - 1.25rem) * 0.5; |
|||
stroke-width: 1.75; |
|||
} |
|||
|
|||
&.icon-left { |
|||
.icon { |
|||
left: ($btn-form-height - 1.25rem) * 0.5; |
|||
right: auto; |
|||
} |
|||
|
|||
.input { |
|||
padding-left: 2rem; |
|||
padding-right: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.avatar { |
|||
background: rgba($muted, 0.1); |
|||
color: $muted; |
|||
display: inline-flex; |
|||
width: 2.5rem; |
|||
height: 2.5rem; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border-radius: 50%; |
|||
vertical-align: bottom; |
|||
|
|||
.icon { |
|||
height: 60%; |
|||
width: 60%; |
|||
} |
|||
} |
|||
|
|||
.avatar-sm { |
|||
width: 1.5rem; |
|||
height: 1.5rem; |
|||
} |
|||
|
|||
.tabs { |
|||
display: flex; |
|||
|
|||
.tab { |
|||
flex: 1; |
|||
text-align: center; |
|||
border-bottom: 1px solid $border; |
|||
padding: 0.25rem 0; |
|||
color: inherit; |
|||
text-decoration: none; |
|||
cursor: pointer; |
|||
|
|||
&.active { |
|||
color: $primary; |
|||
border-bottom-color: $primary; |
|||
} |
|||
|
|||
.icon { |
|||
width: 1rem; |
|||
height: 1rem; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.input-range { |
|||
width: 100%; |
|||
} |
|||
|
|||
.icon-size { |
|||
display: inline-block; |
|||
|
|||
svg { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
|
|||
.icon-size-16 { |
|||
width: 16px; |
|||
height: 16px; |
|||
} |
|||
.icon-size-24 { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
.icon-size-32 { |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
.icon-size-48 { |
|||
width: 48px; |
|||
height: 48px; |
|||
} |
|||
.icon-size-64 { |
|||
width: 64px; |
|||
height: 64px; |
|||
} |
|||
|
|||
.table { |
|||
width: 100%; |
|||
border-collapse: collapse; |
|||
|
|||
td, |
|||
th { |
|||
padding: 0.5rem; |
|||
text-align: left; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.icon { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
} |
|||
|
|||
.td-1 { |
|||
width: 1%; |
|||
} |
|||
|
|||
$border-color: #e0e0e0; |
|||
|
|||
.toolbar { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
} |
|||
|
|||
.buttons { |
|||
display: flex; |
|||
margin-right: 0.5rem; |
|||
margin-bottom: 0.5rem; |
|||
border: 1px solid $border-color; |
|||
border-radius: 3px; |
|||
|
|||
.button + .button { |
|||
border-left: 1px solid $border-color; |
|||
} |
|||
} |
|||
|
|||
.button { |
|||
display: inline-flex; |
|||
width: 2rem; |
|||
height: 2rem; |
|||
align-items: center; |
|||
justify-content: center; |
|||
color: color.mix($dark, #fff, 75%); |
|||
|
|||
svg { |
|||
width: 1.25rem; |
|||
height: 1.25rem; |
|||
} |
|||
} |
|||
|
|||
.text-muted { |
|||
color: $muted; |
|||
} |
|||
|
|||
.text-reset { |
|||
color: inherit; |
|||
text-decoration: none; |
|||
} |
|||
@ -0,0 +1,233 @@ |
|||
$breakpoint: 50rem; |
|||
$primary: #206bc4; |
|||
$muted: #aaaaaa; |
|||
$dark: #354052; |
|||
$light: #fafbfc; |
|||
|
|||
* { |
|||
box-sizing: border-box; |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
html { |
|||
font-size: 16px; |
|||
font-family: |
|||
system-ui, |
|||
-apple-system, |
|||
BlinkMacSystemFont, |
|||
Segoe UI, |
|||
Roboto, |
|||
Helvetica Neue, |
|||
Arial, |
|||
Noto Sans, |
|||
sans-serif, |
|||
Apple Color Emoji, |
|||
Segoe UI Emoji, |
|||
Segoe UI Symbol, |
|||
Noto Color Emoji; |
|||
} |
|||
|
|||
body { |
|||
background: $light; |
|||
font-size: 0.9375rem; |
|||
color: $dark; |
|||
-webkit-font-smoothing: antialiased; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
|
|||
@media print { |
|||
color: #000; |
|||
} |
|||
} |
|||
|
|||
a { |
|||
color: $primary; |
|||
text-decoration: none; |
|||
|
|||
&:hover { |
|||
text-decoration: underline; |
|||
} |
|||
} |
|||
|
|||
.container { |
|||
max-width: 60rem; |
|||
margin: 0 auto; |
|||
padding: 1rem; |
|||
|
|||
@media (max-width: #{$breakpoint}) { |
|||
padding: 0; |
|||
} |
|||
|
|||
@media print { |
|||
padding: 0; |
|||
max-width: 100%; |
|||
} |
|||
} |
|||
|
|||
.box { |
|||
padding: 2rem; |
|||
background: #ffff; |
|||
box-shadow: |
|||
0 0 0 1px rgba(0, 0, 0, 0.05), |
|||
0 1px 1px rgba(0, 0, 0, 0.1); |
|||
page-break-before: always; |
|||
margin-bottom: 2rem; |
|||
|
|||
@media (max-width: #{$breakpoint}) { |
|||
padding: 0.5rem; |
|||
box-shadow: none; |
|||
} |
|||
|
|||
@media print { |
|||
padding: 0; |
|||
box-shadow: none; |
|||
margin-bottom: 0; |
|||
} |
|||
} |
|||
|
|||
.box-title { |
|||
font-size: 1.5rem; |
|||
line-height: 1; |
|||
margin: 0 0 1rem; |
|||
font-weight: 600; |
|||
|
|||
@media print { |
|||
display: none; |
|||
} |
|||
} |
|||
|
|||
.icons-list { |
|||
display: table; |
|||
margin: -0.25rem; |
|||
} |
|||
|
|||
.icons-list-borders { |
|||
.icons-list-icon { |
|||
border-color: $dark; |
|||
} |
|||
} |
|||
|
|||
.icons-list-squares, |
|||
.icons-list-circles { |
|||
.icons-list-icon { |
|||
background: $dark; |
|||
color: $light; |
|||
} |
|||
} |
|||
|
|||
.icons-list-circles { |
|||
.icons-list-icon { |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
|
|||
.icons-list-icon { |
|||
margin: 0.25rem; |
|||
min-width: 2.25rem; |
|||
height: 2.25rem; |
|||
color: inherit; |
|||
border-radius: 3px; |
|||
display: inline-flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 1px solid transparent; |
|||
position: relative; |
|||
page-break-inside: avoid; |
|||
|
|||
&.new-icon { |
|||
&:after { |
|||
content: ''; |
|||
position: absolute; |
|||
top: 2px; |
|||
right: 2px; |
|||
width: 6px; |
|||
height: 6px; |
|||
background: #cc0000; |
|||
border-radius: 50%; |
|||
} |
|||
} |
|||
|
|||
&.active { |
|||
background: #f0f0f0; |
|||
} |
|||
|
|||
@at-root a#{&}:hover { |
|||
opacity: 0.75; |
|||
} |
|||
|
|||
.icon { |
|||
display: block; |
|||
width: 1.5rem; |
|||
height: 1.5rem; |
|||
} |
|||
} |
|||
|
|||
.mb { |
|||
margin-bottom: 2rem; |
|||
} |
|||
|
|||
.icon { |
|||
width: 1em; |
|||
height: 1em; |
|||
vertical-align: -0.15em; |
|||
} |
|||
|
|||
.icon-size { |
|||
display: inline-block; |
|||
|
|||
svg { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
|
|||
.icon-size-16 { |
|||
width: 16px; |
|||
height: 16px; |
|||
} |
|||
.icon-size-24 { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
.icon-size-32 { |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
.icon-size-48 { |
|||
width: 48px; |
|||
height: 48px; |
|||
} |
|||
.icon-size-64 { |
|||
width: 64px; |
|||
height: 64px; |
|||
} |
|||
|
|||
.table { |
|||
width: 100%; |
|||
border-collapse: collapse; |
|||
|
|||
td, |
|||
th { |
|||
padding: 0.5rem; |
|||
text-align: left; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.icon { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
} |
|||
|
|||
.td-1 { |
|||
width: 1%; |
|||
} |
|||
|
|||
.text-muted { |
|||
color: $muted; |
|||
} |
|||
|
|||
.text-reset { |
|||
color: inherit; |
|||
text-decoration: none; |
|||
} |
|||
@ -1,42 +0,0 @@ |
|||
--- |
|||
layout: default |
|||
--- |
|||
|
|||
<div class="container"> |
|||
<div class="box"> |
|||
{% assign i = 0 %} |
|||
<table class="table mb"> |
|||
{% for icon in groupped-icons %} |
|||
<tr> |
|||
<td class="td-1"><a href="#" data-copy class="text-reset">{{ icon.styles.outline.content }}</a></td> |
|||
<td class="td-1"><a href="#" data-copy class="text-reset">{{ icon.styles.filled.content }}</a></td> |
|||
<th><a href="#" data-copy class="text-reset">{{ icon.name }}</a></th> |
|||
<td>{{ icon.data.tags | join: ', ' }}</td> |
|||
<td>{{ icon.data.category }}</td> |
|||
<td>{{ icon.styles.outline.version }}</td> |
|||
</tr> |
|||
{% if icon.data.tags.size == 0 %} |
|||
{% assign i = i | plus: 1 %} |
|||
{% endif %} |
|||
{% endfor %} |
|||
</table> |
|||
|
|||
<p>Untagged: {{ i }}</p> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
<script> |
|||
document.addEventListener('DOMContentLoaded', function() { |
|||
|
|||
document.querySelectorAll('a[data-copy]').forEach(function(a) { |
|||
|
|||
a.addEventListener('click', function(e) { |
|||
e.preventDefault(); |
|||
navigator.clipboard.writeText(this.innerHTML); |
|||
|
|||
return false; |
|||
}); |
|||
}); |
|||
}); |
|||
</script> |
|||
Loading…
Reference in new issue