From 021469f4bda6a4fc45a564f320cc83f472a0007d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sat, 9 Oct 2021 21:04:02 +0200 Subject: [PATCH 01/18] feat: add css compiler --- examples/vite-vue3/App.vue | 7 +++++++ src/core/compilers/css.ts | 20 ++++++++++++++++++++ src/core/compilers/index.ts | 2 ++ src/core/svgId.ts | 3 ++- src/index.ts | 12 +++++++++++- src/types.ts | 2 +- 6 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/core/compilers/css.ts diff --git a/examples/vite-vue3/App.vue b/examples/vite-vue3/App.vue index 97d258e1..091544cb 100644 --- a/examples/vite-vue3/App.vue +++ b/examples/vite-vue3/App.vue @@ -28,6 +28,11 @@

+

CSS Icons

+

+ + +

Collection alias

@@ -40,4 +45,6 @@ diff --git a/src/core/compilers/css.ts b/src/core/compilers/css.ts new file mode 100644 index 00000000..d44ece1a --- /dev/null +++ b/src/core/compilers/css.ts @@ -0,0 +1,20 @@ +// import { ResolvedOptions } from '../../types' +import { Compiler } from './types' + +export const CssCompiler = (( + svg: string, + collection: string, + icon: string, + // options: ResolvedOptions, +) => { + return `.${collection}-${icon} { +background: url(data:image/svg+xml;base64,${Buffer.from(svg, 'utf-8').toString('base64')}) no-repeat center; +background-size: 16px 16px; +height: 16px; +opacity: 0.87; +width: 16px; +max-width: 16px; +display: inline-block; +} +` +}) diff --git a/src/core/compilers/index.ts b/src/core/compilers/index.ts index 0e570327..1742507a 100644 --- a/src/core/compilers/index.ts +++ b/src/core/compilers/index.ts @@ -8,8 +8,10 @@ import { Compiler } from './types' import { Vue2Compiler } from './vue2' import { Vue3Compiler } from './vue3' import { WebComponentsCompiler } from './web-components' +import { CssCompiler } from './css' export const compilers: Record = { + 'css': CssCompiler, 'vue2': Vue2Compiler, 'vue3': Vue3Compiler, 'solid': SolidCompiler, diff --git a/src/core/svgId.ts b/src/core/svgId.ts index 81db1ea9..981e8ced 100644 --- a/src/core/svgId.ts +++ b/src/core/svgId.ts @@ -16,7 +16,8 @@ export function handleSVGId(svg: string) { return `:id="idMap['${id}']"` return full }) - injectScripts = randIdFn + `const idMap = {${Object.values(idMap).join(',')}};` + // eslint-disable-next-line prefer-template + injectScripts = randIdFn + `const idMap = {${Object.values(idMap).join(',')}};` } return { diff --git a/src/index.ts b/src/index.ts index d803e1ad..9b0f70f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,9 @@ const unplugin = createUnplugin((options = {}) => { enforce: 'pre', resolveId(id) { if (isIconPath(id)) { + if (id.endsWith('.css')) + return id + const res = normalizeIconPath(id) .replace(/\.\w+$/i, '') .replace(/^\//, '') @@ -26,7 +29,14 @@ const unplugin = createUnplugin((options = {}) => { async load(id) { const config = await resolved if (isIconPath(id)) { - const code = await generateComponentFromPath(id, config) || null + let code: string | null = null + const css = id.endsWith('.css') + if (css) + code = await generateComponentFromPath(id, { ...config, compiler: 'css' }) || null + + else + code = await generateComponentFromPath(id, config) || null + if (code) { return { code, diff --git a/src/types.ts b/src/types.ts index 9fb19c45..b6adec13 100644 --- a/src/types.ts +++ b/src/types.ts @@ -57,7 +57,7 @@ export interface Options { * * @default (detect automatically, fallback to 'vue3') */ - compiler?: 'vue2' | 'vue3' | 'jsx' | 'solid' | 'svelte' | 'web-components' | 'none' | 'raw' + compiler?: 'vue2' | 'vue3' | 'jsx' | 'solid' | 'svelte' | 'web-components' | 'none' | 'raw' | 'css' /** * JSX style, works only when compiler set to `jsx` From 2cc474c114ae2d4ebe7f6b1752079b5672f3cd64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sat, 9 Oct 2021 21:47:10 +0200 Subject: [PATCH 02/18] chore: add options for css fix: add svg xmlns if missing on source --- src/core/compilers/css.ts | 27 +++++++++++++++++++-------- src/core/options.ts | 2 ++ src/types.ts | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/core/compilers/css.ts b/src/core/compilers/css.ts index d44ece1a..a5af843e 100644 --- a/src/core/compilers/css.ts +++ b/src/core/compilers/css.ts @@ -1,20 +1,31 @@ -// import { ResolvedOptions } from '../../types' +import { ResolvedOptions } from '../../types' import { Compiler } from './types' export const CssCompiler = (( svg: string, collection: string, icon: string, - // options: ResolvedOptions, + options: ResolvedOptions, ) => { + // we need to add the cvg xml namespace + let inlineSvg = svg.includes('xmlns=') + ? svg + : svg.replace(/"/g, '\'').replace(' jsx = guessJSX(), customCollections = {}, autoInstall = false, + css = {}, } = options const webComponents = Object.assign({ @@ -33,6 +34,7 @@ export async function resolveOptions(options: Options): Promise jsx, webComponents, autoInstall, + css, } } diff --git a/src/types.ts b/src/types.ts index b6adec13..6a87f809 100644 --- a/src/types.ts +++ b/src/types.ts @@ -82,6 +82,30 @@ export interface Options { */ iconPrefix?: string } + + /** + * Config for CSS compiler + */ + css?: { + /** + * How to inline the svg as background image. + * + * @default 'svg' + */ + type?: 'svg' | 'base64' + /** + * Scale of icons against 1em + * + * @default 1.2 + */ + scale?: number + /** + * Style apply to CSS icons by default + * + * @default '' + */ + defaultStyle?: string + } } export interface ResolvedOptions extends Required {} From 944659db125fc43cb7bd63666329124c98267b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sat, 9 Oct 2021 21:51:55 +0200 Subject: [PATCH 03/18] chore: add css option on vite-vue3 example fix: use 1.2 instead 1 as default scale --- examples/vite-vue3/vite.config.ts | 3 +++ src/core/compilers/css.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/vite-vue3/vite.config.ts b/examples/vite-vue3/vite.config.ts index cbaa5fca..c2ba9a37 100644 --- a/examples/vite-vue3/vite.config.ts +++ b/examples/vite-vue3/vite.config.ts @@ -18,6 +18,9 @@ const config: UserConfig = { async: () => fs.readFile('assets/giftbox.svg', 'utf-8'), }, }, + // css: { + // type: 'base64', + // }, }), Components({ dts: true, diff --git a/src/core/compilers/css.ts b/src/core/compilers/css.ts index a5af843e..cb9a149a 100644 --- a/src/core/compilers/css.ts +++ b/src/core/compilers/css.ts @@ -17,7 +17,7 @@ export const CssCompiler = (( ? `base64,${Buffer.from(inlineSvg, 'utf-8').toString('base64')}` : `utf8,${inlineSvg}` - const scale = options?.css.scale ?? 1 + const scale = options?.css.scale ?? 1.2 return `.${collection}-${icon} { background-image: url("data:image/svg+xml;${inlineSvg}"); From 1dcd9c0e5fd6737b1b766a25efb4bbfa59d38314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sat, 9 Oct 2021 21:56:05 +0200 Subject: [PATCH 04/18] chore: css compiler comment wording fix: convert always double quotes to single ones --- src/core/compilers/css.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/compilers/css.ts b/src/core/compilers/css.ts index cb9a149a..b8facc00 100644 --- a/src/core/compilers/css.ts +++ b/src/core/compilers/css.ts @@ -7,9 +7,9 @@ export const CssCompiler = (( icon: string, options: ResolvedOptions, ) => { - // we need to add the cvg xml namespace - let inlineSvg = svg.includes('xmlns=') - ? svg + // we need to add the svg xml namespace + let inlineSvg = svg.includes('http://www.w3.org/2000/svg') + ? svg.replace(/"/g, '\'') : svg.replace(/"/g, '\'').replace(' Date: Sat, 9 Oct 2021 22:28:41 +0200 Subject: [PATCH 05/18] chore: change default styles name on css option --- src/core/compilers/css.ts | 2 +- src/types.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/compilers/css.ts b/src/core/compilers/css.ts index b8facc00..972691a7 100644 --- a/src/core/compilers/css.ts +++ b/src/core/compilers/css.ts @@ -25,7 +25,7 @@ height: ${scale}em; width: ${scale}em; background-size: ${scale}em ${scale}em; display: inline-block; -${options.css.defaultStyle || ''} +${options.css.defaultStyles || ''} } ` }) diff --git a/src/types.ts b/src/types.ts index 6a87f809..9210f34f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -100,11 +100,11 @@ export interface Options { */ scale?: number /** - * Style apply to CSS icons by default + * Styles to apply to CSS icons by default * * @default '' */ - defaultStyle?: string + defaultStyles?: string } } From ee1cfb0f5c00cbe8cb066a2bf54305a5819794cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 00:27:39 +0200 Subject: [PATCH 06/18] fix(custom): prevent add width and height twice for css compiler --- src/core/custom.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/core/custom.ts b/src/core/custom.ts index d19af723..05933c1a 100644 --- a/src/core/custom.ts +++ b/src/core/custom.ts @@ -25,8 +25,22 @@ export async function getCustomIcon( const scale = options?.scale || 1 if (result) { - if (!result.startsWith('') + let idx = result.indexOf('width') + if (idx > -1 && closeSvg > idx) + return result + idx = result.indexOf('height') + if (idx > -1 && closeSvg > idx) + return result + } + return result.replace(' Date: Sun, 10 Oct 2021 00:27:59 +0200 Subject: [PATCH 07/18] chore: simplify css compiler --- src/core/compilers/css.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/core/compilers/css.ts b/src/core/compilers/css.ts index 972691a7..dda336dc 100644 --- a/src/core/compilers/css.ts +++ b/src/core/compilers/css.ts @@ -7,23 +7,19 @@ export const CssCompiler = (( icon: string, options: ResolvedOptions, ) => { - // we need to add the svg xml namespace - let inlineSvg = svg.includes('http://www.w3.org/2000/svg') - ? svg.replace(/"/g, '\'') - : svg.replace(/"/g, '\'').replace(' Date: Sun, 10 Oct 2021 00:28:33 +0200 Subject: [PATCH 08/18] fix: remove type on css option for complex svgs --- src/types.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/types.ts b/src/types.ts index 9210f34f..f7c84167 100644 --- a/src/types.ts +++ b/src/types.ts @@ -87,12 +87,6 @@ export interface Options { * Config for CSS compiler */ css?: { - /** - * How to inline the svg as background image. - * - * @default 'svg' - */ - type?: 'svg' | 'base64' /** * Scale of icons against 1em * From 1d6349d0351616431cb5123ec861b7b80502ed1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 00:29:23 +0200 Subject: [PATCH 09/18] chore: remove typs css option from vite-vue3 example config --- examples/vite-vue3/vite.config.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/vite-vue3/vite.config.ts b/examples/vite-vue3/vite.config.ts index c2ba9a37..cbaa5fca 100644 --- a/examples/vite-vue3/vite.config.ts +++ b/examples/vite-vue3/vite.config.ts @@ -18,9 +18,6 @@ const config: UserConfig = { async: () => fs.readFile('assets/giftbox.svg', 'utf-8'), }, }, - // css: { - // type: 'base64', - // }, }), Components({ dts: true, From 84f8ff3901d4ef075273f638ebc002e106556a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 00:30:13 +0200 Subject: [PATCH 10/18] chore: add css icons for custom collections --- examples/vite-vue3/App.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/vite-vue3/App.vue b/examples/vite-vue3/App.vue index 091544cb..adf4fafa 100644 --- a/examples/vite-vue3/App.vue +++ b/examples/vite-vue3/App.vue @@ -32,6 +32,9 @@

+ + +

Collection alias

@@ -47,4 +50,7 @@ import MdiStore24Hour from 'virtual:icons/mdi/store-24-hour' import MdiAlarmOff from 'virtual:icons/mdi/alarm-off' import 'virtual:icons/mdi/alarm-off.css' import '~icons/mdi/account.css' +import '~icons/custom/steering-wheel.css' +import '~icons/icon-park/abnormal.css' +import '~icons/inline/foo.css' From 311167abd81dbc08dca8d06ffc1dad7278d93a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 00:32:01 +0200 Subject: [PATCH 11/18] chore: add `types/css.d.ts` --- types/css.d.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 types/css.d.ts diff --git a/types/css.d.ts b/types/css.d.ts new file mode 100644 index 00000000..8b590316 --- /dev/null +++ b/types/css.d.ts @@ -0,0 +1,9 @@ +declare module 'virtual:icons/*.css' { + const css: string + export default css +} + +declare module '~icons/*.css' { + const css: string + export default css +} From 945d7382bbd83139e8744e3e5792e647a145ef8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 00:53:21 +0200 Subject: [PATCH 12/18] chore: more css icons on vite-vue3 and some styling --- examples/vite-vue3/App.vue | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/vite-vue3/App.vue b/examples/vite-vue3/App.vue index adf4fafa..1266996c 100644 --- a/examples/vite-vue3/App.vue +++ b/examples/vite-vue3/App.vue @@ -30,11 +30,14 @@

CSS Icons

- + + + - + +

Collection alias

@@ -48,9 +51,18 @@ + + From 1252269c1ca26a21d23e2b3485895caf9840a373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 00:57:12 +0200 Subject: [PATCH 13/18] chore: add comment to avoid removing `virtual:icons/*.css` --- examples/vite-vue3/App.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/vite-vue3/App.vue b/examples/vite-vue3/App.vue index 1266996c..eb9e661f 100644 --- a/examples/vite-vue3/App.vue +++ b/examples/vite-vue3/App.vue @@ -51,10 +51,11 @@ + From 477586e651c345ec0b0cd4e0b21a203c57ac6f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 02:41:58 +0200 Subject: [PATCH 17/18] docs: add css icons to readme file --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index f72a656c..0edb83a5 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Access thousands of icons as components **on-demand** universally. - ๐Ÿคน **Any** icon sets - 100+ popular sets with over 10,000 icons, logos, emojis, etc. Powered by [Iconify](https://github.com/iconify/iconify). - ๐Ÿ“ฆ **Major** build tools - Vite, Webpack, Rollup, Nuxt, etc. Powered by [unplugin](https://github.com/unjs/unplugin). - ๐Ÿชœ **Major** frameworks - Vanilla, Web Components, React, Vue 3, Vue 2, Solid, Svelte, and more. [Contribute](./src/core/compiles). + - ๐Ÿ—ƒ๏ธ **CSS** icons - Use icons as css stylesheets with or without any framework (experimental). - ๐Ÿฑ **Any** combinations of them! - โ˜๏ธ On-demand - Only bundle the icons you really use, while having all the options. - ๐Ÿ–จ SSR / SSG friendly - Ship the icons with your page, no more FOUC. @@ -650,6 +651,23 @@ IconsResolver({ ``` +### CSS Icons + +You can use svg icons as a `css stylesheet` (no framework required): +```ts +import '~icons/{collection}/{icon}.css' +``` + +then add an `html` element with a `class` with a name following the convention: `{collection}-{icon}`. + +For example: +```html + + +``` + ### Collection Aliases When using component resolver, you have to use the name of the collection that can be long or redundant: for example, From ec3e53e6d17366389e2ca7f21c6963fe6e4c5e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez=20Jim=C3=A9nez?= Date: Sun, 10 Oct 2021 12:18:37 +0200 Subject: [PATCH 18/18] docs: update class name on css icon example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0edb83a5..e5280bd9 100644 --- a/README.md +++ b/README.md @@ -662,7 +662,7 @@ then add an `html` element with a `class` with a name following the convention: For example: ```html - +