├── .changeset
├── README.md
└── config.json
├── .eslintignore
├── .eslintrc
├── .github
├── composite-actions
│ └── install
│ │ └── action.yml
└── workflows
│ ├── quality.yml
│ ├── release.yml
│ └── static.yml
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── package.json
├── packages
├── config
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
├── types
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
└── variants
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── package.json
│ ├── src
│ ├── create-svg.ts
│ ├── index.ts
│ └── resolve-icons
│ │ ├── index.ts
│ │ ├── resolve-collection-function.ts
│ │ ├── resolve-collection-object.ts
│ │ ├── resolve-collection-string.ts
│ │ └── resolve-icon-entries.ts
│ └── tsconfig.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── site
├── .gitignore
├── index.html
├── package.json
├── panda.config.ts
├── postcss.config.cjs
├── public
└── vite.svg
├── src
├── App.tsx
├── index.css
└── main.tsx
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
/.changeset/README.md:
--------------------------------------------------------------------------------
1 | # Changesets
2 |
3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with
4 | multi-package repos, or single-package repos to help you version and publish your code. You can find the full
5 | documentation for it [in our repository](https://github.com/changesets/changesets)
6 |
7 | We have a quick list of common questions to get you started engaging with this project in
8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
9 |
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
3 | "changelog": "@changesets/cli/changelog",
4 | "commit": false,
5 | "fixed": [],
6 | "linked": [],
7 | "access": "restricted",
8 | "baseBranch": "main",
9 | "updateInternalDependencies": "patch",
10 | "ignore": [
11 | "sandbox-vite"
12 | ]
13 | }
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | *.d.ts
2 | *.js
3 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
4 | "env": {
5 | "node": true,
6 | "browser": true
7 | },
8 | "rules": {
9 | "no-prototype-builtins": "off",
10 | "@typescript-eslint/no-explicit-any": "off",
11 | "@typescript-eslint/explicit-module-boundary-types": "off",
12 | "@typescript-eslint/no-non-null-assertion": "off",
13 | "@typescript-eslint/ban-ts-comment": "off",
14 | "@typescript-eslint/no-var-requires": "off",
15 | "@typescript-eslint/ban-types": "off",
16 | "@typescript-eslint/no-unused-vars": [
17 | "error",
18 | {
19 | "varsIgnorePattern": "^_",
20 | "argsIgnorePattern": "^_",
21 | "ignoreRestSiblings": true
22 | }
23 | ]
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.github/composite-actions/install/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Install'
2 | description: 'Sets up Node.js and runs install'
3 |
4 | runs:
5 | using: composite
6 | steps:
7 | - uses: pnpm/action-setup@v2.2.4
8 | with:
9 | version: 7
10 |
11 | - name: Setup Node.js
12 | uses: actions/setup-node@v3
13 | with:
14 | node-version: 16.x
15 | registry-url: 'https://registry.npmjs.org'
16 | cache: 'pnpm'
17 |
18 | - name: Setup Git User
19 | shell: bash
20 | run: |
21 | git config --global user.email "anubra266@gmail.com"
22 | git config --global user.name "Abraham Anuoluwapo"
23 |
24 | - name: Install dependencies
25 | shell: bash
26 | run: pnpm install
27 |
--------------------------------------------------------------------------------
/.github/workflows/quality.yml:
--------------------------------------------------------------------------------
1 | name: Quality
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | concurrency:
12 | group: ${{ github.workflow }}-${{ github.ref }}
13 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
14 |
15 | jobs:
16 | eslint:
17 | name: ESLint
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Checkout
21 | uses: actions/checkout@v3
22 |
23 | - name: Install
24 | uses: ./.github/composite-actions/install
25 |
26 | - name: Run ESLint
27 | run: pnpm lint
28 | env:
29 | NODE_OPTIONS: "--max-old-space-size=4096"
30 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | push:
5 | paths:
6 | - ".changeset/**"
7 | - "packages/**"
8 | branches:
9 | - main
10 |
11 | jobs:
12 | release:
13 | name: Release
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Checkout
17 | uses: actions/checkout@v3
18 | with:
19 | fetch-depth: 0
20 |
21 | - name: Install
22 | uses: ./.github/composite-actions/install
23 |
24 | - name: Build packages
25 | run: pnpm build
26 |
27 | - name: Create release Pull Request or publish to NPM
28 | id: changesets
29 | uses: changesets/action@v1
30 | with:
31 | publish: pnpm release
32 | commit: "ci(changesets): version packages"
33 | setupGitUser: false
34 | env:
35 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
36 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38 |
39 | - name: Release to dev tag
40 | if: steps.changesets.outputs.published != 'true'
41 | run: |
42 | git checkout main
43 | pnpm changeset version --snapshot dev
44 | pnpm changeset publish --tag dev
45 | env:
46 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48 |
--------------------------------------------------------------------------------
/.github/workflows/static.yml:
--------------------------------------------------------------------------------
1 | # Simple workflow for deploying static content to GitHub Pages
2 | name: Deploy Demo page
3 |
4 | on:
5 | # Runs on pushes targeting the default branch
6 | push:
7 | branches: ["main"]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13 | permissions:
14 | contents: read
15 | pages: write
16 | id-token: write
17 |
18 | # Allow one concurrent deployment
19 | concurrency:
20 | group: "pages"
21 | cancel-in-progress: true
22 |
23 | env:
24 | SITE_PATH: "site"
25 |
26 | jobs:
27 | build:
28 | name: Build
29 | runs-on: ubuntu-latest
30 | steps:
31 | - name: Checkout
32 | uses: actions/checkout@v3
33 | - name: Install
34 | uses: ./.github/composite-actions/install
35 | - name: Setup Node
36 | uses: actions/setup-node@v3
37 | - name: Setup Pages
38 | id: pages
39 | uses: actions/configure-pages@v2
40 | - name: Build with Vite
41 | run: |
42 | pnpm build
43 | working-directory: ${{ env.SITE_PATH }}
44 | - name: Upload artifact
45 | uses: actions/upload-pages-artifact@v1
46 | with:
47 | path: ${{ env.SITE_PATH }}/dist_site
48 |
49 | deploy:
50 | environment:
51 | name: github-pages
52 | url: ${{ steps.deployment.outputs.page_url }}
53 | needs: build
54 | runs-on: ubuntu-latest
55 | name: Deploy
56 | steps:
57 | - name: Deploy to GitHub Pages
58 | id: deployment
59 | uses: actions/deploy-pages@v1
60 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # .gitignore
2 | node_modules
3 | dist
4 | build
5 | dist_site
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | strict-peer-dependencies=false
2 | enable-pre-post-scripts=true
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | coverage
4 | .next
5 | build
6 | *.hbs
7 | *.d.ts
8 | site/dist_site
9 | site/styled-system
10 | .github
11 | .changeset
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "printWidth": 120,
4 | "bracketSpacing": true,
5 | "jsxSingleQuote": false,
6 | "proseWrap": "always",
7 | "semi": false,
8 | "tabWidth": 2,
9 | "trailingComma": "all"
10 | }
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 anubra266
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 😌
5 |
6 | css-picons
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Use any icons with Pure CSS in CSS Panda
29 |
30 |
31 |
32 |
33 |
34 |
35 | ## About
36 |
37 | Use any icons with Pure CSS in [CSS Panda](https://github.com/chakra-ui/panda). 'Twas Inspired by
38 | [@unocss/preset-icons](https://github.com/unocss/unocss/tree/main/packages/preset-icons/)
39 |
40 | ## Install
41 |
42 | ```sh
43 | npm i -D @css-picons/config @iconify-json/[the-collection-you-want]
44 | ```
45 |
46 | We use [Iconify](https://iconify.design) as our data source of icons. You need to install the corresponding iconset in
47 | `devDependencies` by following the `@iconify-json/*` pattern. For example, `@iconify-json/mdi` for
48 | [Material Design Icons](https://materialdesignicons.com/), `@iconify-json/tabler` for
49 | [Tabler](https://tabler-icons.io/). You can refer to [Icônes](https://icones.js.org/) or
50 | [Iconify](https://icon-sets.iconify.design/) for all the collections available.
51 |
52 | If you prefer to install the all the icon sets available on Iconify at once (~130MB):
53 |
54 | ```bash
55 | npm i -D @iconify/json
56 | ```
57 |
58 | > Even if you do this, only the ones used in your code will be packaged by panda. That's nice.
59 |
60 | ## Configuration
61 |
62 | In your `panda.config.*` file, import `cssPicons` from `@css-picons/config`, then add it to presets
63 |
64 | ```ts
65 | import { cssPicons } from '@css-picons/config'
66 | export default defineConfig({
67 | presets: [
68 | // ...
69 | cssPicons({
70 | // Specify all the icon sets you'll be using
71 | collections: ['mdi'],
72 | }),
73 | ],
74 | })
75 | ```
76 |
77 | Then make sure your `theme` is extendable, if you have configured it.
78 |
79 | ```js
80 | // panda.config.*
81 | export default defineConfig({
82 | //...
83 | theme: {
84 | extend: {
85 | // ...
86 | },
87 | },
88 | })
89 | ```
90 |
91 | ## Usage
92 |
93 | Now you can use it in your components in all the ways `css-panda` allows through the `icon` recipe which is exported
94 | from your design system. The icon name follows the format `:`
95 |
96 | ```js
97 | import { icon } from '../panda/recipes'
98 | return (
99 |
108 | )
109 | ```
110 |
111 | **Result**:
112 |
113 |
114 |
115 | #### Usage in other ways
116 |
117 | ```js
118 | // A basic anchor icon from Phosphor icons
119 | const className = icon({ name: 'ph:anchor-simple-thin' })
120 | // An orange alarm from Material Design Icons
121 | const className = cx(icon({ name: 'mdi:alarm' }), css({ color: 'orange.400' }))
122 | // A large react logo
123 | const className = cx(icon({ name: 'logos:react' }), css({ fontSize: '3xl' }))
124 | // Sun in light mode, Moon in dark mode, from Carbon
125 | const className = icon({ name: { base: 'carbon:sun', _dark: 'carbon:moon' } })
126 | // Twemoji of laugh, turns to tear on hovering
127 | const className = icon({
128 | name: {
129 | base: 'twemoji:grinning-face-with-smiling-eyes',
130 | _hover: 'twemoji:face-with-tears-of-joy',
131 | },
132 | })
133 | ```
134 |
135 | ### JSX
136 |
137 | When using in `jsx` you might want to use it in a reusable component, in such cases you have to tell `css-panda` the
138 | name of the component so it can watch it when generating styles. An example:
139 |
140 | ```js
141 | function AppIcon(props: IconVariants) {
142 | return (
143 |
151 | )
152 | }
153 | // Somewhere else
154 | return
155 | ```
156 |
157 | You tell `panda` to watch the external component by using the `jsx` key in the config.
158 |
159 | ```ts
160 | import { cssPicons } from '@css-picons/config'
161 | export default defineConfig({
162 | presets: [
163 | // ...
164 | cssPicons({
165 | // ...
166 | jsx: 'AppIcon',
167 | }),
168 | ],
169 | })
170 | ```
171 |
172 | **Note:** Panda automatically tracks components named as the capitalized version of the identifier. e.g. If your
173 | identifier is daocons, a component called `Daocons` that consumes it will be automatically tracked. In this case, we
174 | automatically track components named `Icon`.
175 |
176 | ### Identifier
177 |
178 | By default, you export `icon` from recipes which is then consumed to render the icons. But you can change this in the
179 | config with the `identifier` key.
180 |
181 | ```ts
182 | import { cssPicons } from '@css-picons/config'
183 | export default defineConfig({
184 | presets: [
185 | // ...
186 | cssPicons({
187 | // ...
188 | identifier: 'cssIcon',
189 | }),
190 | ],
191 | })
192 | ```
193 |
194 | Then export and use the new identifier in your project instead.
195 |
196 | ```js
197 | import { cssIcon } from '../panda/recipes'
198 | return (
199 |
208 | )
209 | ```
210 |
211 | ### Extra Styles
212 |
213 | You can provide extra styles to control the default behavior of the icons. You could make icons vertically aligned and
214 | inline by default by the following example:
215 |
216 | ```ts
217 | import { cssPicons } from '@css-picons/config'
218 | export default defineConfig({
219 | presets: [
220 | // ...
221 | cssPicons({
222 | // ...
223 | styles: {
224 | verticalAlign: 'middle',
225 | display: 'inline-block',
226 | },
227 | }),
228 | ],
229 | })
230 | ```
231 |
232 | ### Modes Overriding
233 |
234 | By default, `css-picons` will choose the rendering modes automatically for each icon based on the icons'
235 | characteristics. You can read more in this [blog post](https://antfu.me/posts/icons-in-pure-css). In some cases, you may
236 | want to explicitly set the rendering modes for each icon.
237 |
238 | - `?bg` for `background-img` - renders the icon as a background image
239 | - `?mask` for `mask` - renders the icon as a mask image
240 |
241 | For example, `vscode-icons:file-type-light-pnpm`, an icon with colors (the `svg` doesn't contain `currentColor`) that
242 | will be rendered as a background image. Use `vscode-icons:file-type-light-pnpm?mask` to render it as a mask image and
243 | bypass it's colors.
244 |
245 | #### Default mode
246 |
247 | You can also set the default mode in your config with the `mode` key. It's `auto` by default which means `css-picons`
248 | automatically selects a mode based on it's perception of the icon.
249 |
250 | ```ts
251 | export default defineConfig({
252 | presets: [
253 | // ...
254 | cssPicons({
255 | // ...
256 | mode: 'mask',
257 | }),
258 | ],
259 | })
260 | ```
261 |
262 | ### Custom collections
263 |
264 | You can also provide your own custom collections by passing a tuple.
265 |
266 | The **first** item in the tuple is the collection's name.
267 |
268 | The **second** can either be a function or an object.
269 |
270 | **Basic example**
271 |
272 | ```ts
273 | export default defineConfig({
274 | presets: [
275 | // ...
276 | cssPicons({
277 | // ...
278 | collections: [
279 | // ...
280 | [
281 | 'custom',
282 | {
283 | circle: '',
284 | },
285 | ],
286 | ],
287 | }),
288 | ],
289 | })
290 | ```
291 |
292 | Then use it through the `custom` icon name:
293 |
294 | ```js
295 | import { icon } from '../panda/recipes'
296 | return
297 | ```
298 |
299 | You can also provide a function that resolves to a string:
300 |
301 | **Read from file**
302 |
303 | ```ts
304 | export default defineConfig({
305 | presets: [
306 | // ...
307 | cssPicons({
308 | // ...
309 | collections: [
310 | // ...
311 | [
312 | 'custom',
313 | {
314 | vite: () => fs.readFile('./public/vite.svg', 'utf-8'),
315 | },
316 | ],
317 | ],
318 | }),
319 | ],
320 | })
321 | ```
322 |
323 | Usage:
324 |
325 | ```js
326 | import { icon } from '../panda/recipes'
327 | return
328 | ```
329 |
330 | **Fetch icon svg from a remote server**
331 |
332 | ```ts
333 | // Native fetch is not defined in the node process
334 | import fetch from 'node-fetch'
335 |
336 | export default defineConfig({
337 | presets: [
338 | // ...
339 | cssPicons({
340 | // ...
341 | collections: [
342 | // ...
343 | [
344 | 'solar',
345 | {
346 | 'airbuds-outline': async () => {
347 | return await fetch('https://api.iconify.design/solar:airbuds-outline.svg?color=%23888888').then((res) =>
348 | res.text(),
349 | )
350 | },
351 | },
352 | ],
353 | ],
354 | }),
355 | ],
356 | })
357 | ```
358 |
359 | Usage:
360 |
361 | ```js
362 | import { icon } from '../panda/recipes'
363 | return
364 | ```
365 |
366 | **Iconify JSON or function returning iconify JSON**
367 |
368 | ```ts
369 | import feIconsData from '@iconify-json/fe/icons.json'
370 | import phIconsData from '@iconify-json/ph/icons.json'
371 |
372 | export default defineConfig({
373 | presets: [
374 | // ...
375 | cssPicons({
376 | // ...
377 | collections: [
378 | // ...
379 | ['fe', feIconsData],
380 | ['ph', () => phIconsData],
381 | ],
382 | }),
383 | ],
384 | })
385 | ```
386 |
387 | Usage:
388 |
389 | ```js
390 | import { icon } from '../panda/recipes'
391 | return
392 | return
393 | ```
394 |
395 | **Dynamic import**
396 |
397 | ```ts
398 | export default defineConfig({
399 | presets: [
400 | // ...
401 | cssPicons({
402 | // ...
403 | collections: [
404 | // ...
405 | ['carbon', () => import('@iconify-json/carbon/icons.json').then((i) => i.default as any)],
406 | ],
407 | }),
408 | ],
409 | })
410 | ```
411 |
412 | Usage:
413 |
414 | ```js
415 | import { icon } from '../panda/recipes'
416 | return
417 | ```
418 |
419 | **Fetch icons data from a remote server**
420 |
421 | ```ts
422 | // Native fetch is not defined in the node process
423 |
424 | export default defineConfig({
425 | presets: [
426 | // ...
427 | cssPicons({
428 | // ...
429 | collections: [
430 | // ...
431 | [
432 | 'circle-flags',
433 | async () => {
434 | //* fetch iconifyJson from a remote server:
435 | //! We use node-fetch package because we can't access the native fetch
436 | return await fetch(
437 | 'https://raw.githubusercontent.com/iconify/icon-sets/master/json/circle-flags.json',
438 | ).then((res) => res.json())
439 | },
440 | ],
441 | ],
442 | }),
443 | ],
444 | })
445 | ```
446 |
447 | Usage:
448 |
449 | ```js
450 | import { icon } from '../panda/recipes'
451 | return
452 | ```
453 |
454 | ### Transforming icons
455 |
456 | We provide a transform method which lets you transform icons when loading, for example adding fill attribute with
457 | currentColor.
458 |
459 | ```js
460 | export default defineConfig({
461 | presets: [
462 | // ...
463 | cssPicons({
464 | // ...
465 | transform(svg) {
466 | return svg.replace(/#fff/, 'currentColor')
467 | },
468 | }),
469 | ],
470 | })
471 | ```
472 |
473 | We also provide the `collection` and `icon` so you can streamline your transformations.
474 |
475 | ```js
476 | export default defineConfig({
477 | presets: [
478 | // ...
479 | cssPicons({
480 | // ...
481 | transform(svg) {
482 | // do not apply fill to this icons on this collection
483 | if (collection === 'custom' && icon === 'circle') return svg
484 | return svg.replace(/#fff/, 'currentColor')
485 | },
486 | }),
487 | ],
488 | })
489 | ```
490 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "css-picons",
3 | "version": "0.0.1",
4 | "description": "Pure CSS icons for css panda",
5 | "main": "index.js",
6 | "scripts": {
7 | "prepare": "pnpm build",
8 | "dev": "pnpm -r --parallel --filter=./packages/** dev",
9 | "build:types": "pnpm --filter=./packages/types build",
10 | "build:variants": "pnpm --filter=./packages/variants build",
11 | "build:config": "pnpm --filter=./packages/config build",
12 | "build": "pnpm build:types && pnpm build:variants && pnpm build:config",
13 | "check": "pnpm build && pnpm typecheck && pnpm lint && pnpm test run",
14 | "clean": "pnpm -r --parallel exec rm -rf dist .turbo *.log",
15 | "reset": "pnpm -r --parallel exec rm -rf node_modules && rm -rf node_modules",
16 | "lint": "eslint packages --ext .ts",
17 | "prettier": "prettier --check .",
18 | "prettier-fix": "prettier --write .",
19 | "version": "changeset version",
20 | "release": "changeset publish",
21 | "release-dev": "changeset version --snapshot dev && changeset publish --tag dev"
22 | },
23 | "keywords": [],
24 | "author": "Abraham A. ",
25 | "license": "MIT",
26 | "dependencies": {
27 | "@changesets/changelog-github": "0.4.8",
28 | "@changesets/cli": "2.26.1",
29 | "@types/node": "20.1.1",
30 | "@typescript-eslint/eslint-plugin": "5.59.5",
31 | "@typescript-eslint/parser": "5.59.5",
32 | "concurrently": "^8.0.1",
33 | "prettier": "2.8.8",
34 | "tsup": "6.7.0",
35 | "typescript": "5.0.4",
36 | "vitest": "0.31.0"
37 | }
38 | }
--------------------------------------------------------------------------------
/packages/config/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | node_modules
4 | dist
--------------------------------------------------------------------------------
/packages/config/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @css-picons/config
2 |
3 | ## 0.0.5
4 |
5 | ### Patch Changes
6 |
7 | - b599663: Improve deep instantiated return type
8 | - Updated dependencies [b599663]
9 | - @css-picons/types@0.0.5
10 | - @css-picons/variants@0.0.5
11 |
12 | ## 0.0.4
13 |
14 | ### Patch Changes
15 |
16 | - 6892674: - Add transform method for mutating icon svgs.
17 | - Add more ways of loading icons.
18 | - Updated dependencies [6892674]
19 | - @css-picons/variants@0.0.4
20 | - @css-picons/types@0.0.4
21 |
22 | ## 0.0.3
23 |
24 | ### Patch Changes
25 |
26 | - 98f601d: Allow all configurations permitted in recipes by panda css
27 | - Updated dependencies [377f0a2]
28 | - Updated dependencies [98f601d]
29 | - @css-picons/variants@0.0.3
30 | - @css-picons/types@0.0.3
31 |
32 | ## 0.0.2
33 |
34 | ### Patch Changes
35 |
36 | - b613efd: Allow custom collection
37 | - 75e99ce: Bump packages
38 | - Updated dependencies [b613efd]
39 | - Updated dependencies [75e99ce]
40 | - @css-picons/variants@0.0.2
41 | - @css-picons/types@0.0.2
42 |
43 | ## 0.0.1
44 |
45 | ### Patch Changes
46 |
47 | - c9c44db: Initial release
48 | - Updated dependencies [c9c44db]
49 | - @css-picons/types@0.0.1
50 | - @css-picons/variants@0.0.1
51 |
--------------------------------------------------------------------------------
/packages/config/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@css-picons/config",
3 | "version": "0.0.5",
4 | "license": "MIT",
5 | "description": "Pure CSS icons for css panda",
6 | "main": "dist/index.js",
7 | "module": "dist/index.mjs",
8 | "types": "dist/index.d.ts",
9 | "author": "Abraham - anubra266 ",
10 | "scripts": {
11 | "build": "tsup src/index.ts --format=cjs,esm --shims --dts",
12 | "dev": "pnpm build --watch",
13 | "test": "echo \"Error: no test specified\""
14 | },
15 | "files": [
16 | "dist"
17 | ],
18 | "sideEffects": false,
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "dependencies": {
23 | "@css-picons/types": "workspace:*",
24 | "@css-picons/variants": "workspace:*"
25 | },
26 | "devDependencies": {
27 | "@pandacss/dev": "dev"
28 | }
29 | }
--------------------------------------------------------------------------------
/packages/config/src/index.ts:
--------------------------------------------------------------------------------
1 | import { definePreset } from '@pandacss/dev'
2 | import type { CssPiconsOptions } from '@css-picons/types'
3 | import { getNameVariants } from '@css-picons/variants'
4 |
5 | export const cssPicons = async (options: CssPiconsOptions): Promise => {
6 | const { identifier = 'icon', styles, variants: variantsConfig, ...rest } = options
7 | const nameVariants = await getNameVariants(options)
8 |
9 | const base = Object.assign(
10 | {
11 | width: '1em',
12 | height: '1em',
13 | },
14 | styles,
15 | )
16 |
17 | const variants = Object.assign({}, variantsConfig, {
18 | name: nameVariants,
19 | })
20 |
21 | const recipe = Object.assign(
22 | {
23 | name: 'icon',
24 | description: 'Icon style',
25 | base,
26 | variants,
27 | },
28 | rest,
29 | )
30 |
31 | return definePreset({
32 | theme: {
33 | extend: {
34 | recipes: {
35 | [identifier]: recipe,
36 | },
37 | },
38 | },
39 | })
40 | }
41 |
42 | export default cssPicons
43 |
--------------------------------------------------------------------------------
/packages/config/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
3 | "include": ["src", "types"],
4 | "compilerOptions": {
5 | "module": "esnext",
6 | "lib": ["dom", "esnext"],
7 | "importHelpers": false,
8 | // output .d.ts declaration files for consumers
9 | "declaration": true,
10 | // output .js.map sourcemap files for consumers
11 | "sourceMap": true,
12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index
13 | "rootDir": "./src",
14 | // stricter type-checking for stronger correctness. Recommended by TS
15 | "strict": true,
16 | // linter checks for common issues
17 | "noImplicitReturns": true,
18 | "noFallthroughCasesInSwitch": true,
19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | // use Node's module resolution algorithm, instead of the legacy TS one
23 | "moduleResolution": "node",
24 | // transpile JSX to React.createElement
25 | "jsx": "react",
26 | // interop between ESM and CJS modules. Recommended by TS
27 | "esModuleInterop": true,
28 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
29 | "skipLibCheck": true,
30 | // error out if import and file system have a casing mismatch. Recommended by TS
31 | "forceConsistentCasingInFileNames": true,
32 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
33 | "noEmit": true,
34 | "resolveJsonModule": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/types/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | node_modules
4 | dist
--------------------------------------------------------------------------------
/packages/types/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @css-picons/types
2 |
3 | ## 0.0.5
4 |
5 | ### Patch Changes
6 |
7 | - b599663: Improve deep instantiated return type
8 |
9 | ## 0.0.4
10 |
11 | ### Patch Changes
12 |
13 | - 6892674: - Add transform method for mutating icon svgs.
14 | - Add more ways of loading icons.
15 |
16 | ## 0.0.3
17 |
18 | ### Patch Changes
19 |
20 | - 377f0a2: Merge custom collections into `collections` key
21 | - 98f601d: Allow all configurations permitted in recipes by panda css
22 |
23 | ## 0.0.2
24 |
25 | ### Patch Changes
26 |
27 | - b613efd: Allow custom collection
28 | - 75e99ce: Bump packages
29 |
30 | ## 0.0.1
31 |
32 | ### Patch Changes
33 |
34 | - c9c44db: Initial release
35 |
--------------------------------------------------------------------------------
/packages/types/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@css-picons/types",
3 | "version": "0.0.5",
4 | "license": "MIT",
5 | "description": "Pure CSS icons for css panda",
6 | "main": "dist/index.js",
7 | "module": "dist/index.mjs",
8 | "types": "dist/index.d.ts",
9 | "author": "Abraham - anubra266 ",
10 | "scripts": {
11 | "build": "tsup src/index.ts --format=cjs,esm --shims --dts",
12 | "dev": "pnpm build --watch",
13 | "test": "echo \"Error: no test specified\""
14 | },
15 | "files": [
16 | "dist"
17 | ],
18 | "sideEffects": false,
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "dependencies": {
23 | "@iconify/collections": "^1.0.238",
24 | "@iconify/types": "^2.0.0"
25 | },
26 | "devDependencies": {
27 | "@pandacss/types": "dev"
28 | }
29 | }
--------------------------------------------------------------------------------
/packages/types/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { RecipeConfig, SystemStyleObject } from '@pandacss/types'
2 | import type iconifyCollections from '@iconify/collections/collections.json'
3 | import type { IconifyJSON } from '@iconify/types'
4 |
5 | export { IconifyJSON }
6 |
7 | export type CollectionIcon = { collection: string; icon: string; svg: string | null }
8 |
9 | type IconifyCollections = keyof typeof iconifyCollections
10 |
11 | type CustomCollectionValue = string | (() => string) | (() => Promise)
12 | export type CustomIconRecord = Record | IconifyJSON
13 |
14 | type CustomIconFunctionReturn = IconifyCollections | CustomIconRecord
15 | export type CustomIconFunction = () => CustomIconFunctionReturn | Promise
16 |
17 | export type CustomCollection = IconifyCollections | CustomIconRecord | CustomIconFunction
18 |
19 | export type Collection = IconifyCollections | [string, CustomCollection]
20 |
21 | export interface CssPiconsOptions extends Omit, 'name' | 'description' | 'base'> {
22 | /**
23 | * The jsx elements to track that consumes the exposed recipe.
24 | *
25 | * @default Icon
26 | */
27 | jsx?: RecipeConfig<{}>['jsx']
28 | /**
29 | * The identifier for the exposed recipe
30 | *
31 | * @default icon
32 | */
33 | identifier?: string
34 | collections: Collection[]
35 | /**
36 | * Extra styles applied to the icons by default
37 | *
38 | * @default {}
39 | */
40 | styles?: SystemStyleObject
41 | /**
42 | * Mode of generated CSS icons.
43 | *
44 | * - `mask` - use background color and the `mask` property for monochrome icons
45 | * - `bg` - use background image for the icons, colors are static
46 | * - `auto` - smartly decide mode between `mask` and `background-img` per icon based on its style
47 | *
48 | * @default 'auto'
49 | * @see https://antfu.me/posts/icons-in-pure-css
50 | */
51 | mode?: 'mask' | 'bg' | 'auto'
52 |
53 | /**
54 | *
55 | * Transform method lets you transform icons when loading, for example adding fill attribute with currentColor
56 | * @param svg the svg string
57 | * @param collection collection name
58 | * @param icon icon name
59 | * @returns tranformed svg string
60 | *
61 | */
62 | transform?: (svg: string, collection: string, icon: string) => string
63 | }
64 |
--------------------------------------------------------------------------------
/packages/types/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
3 | "include": ["src", "types"],
4 | "compilerOptions": {
5 | "module": "esnext",
6 | "lib": ["dom", "esnext"],
7 | "importHelpers": false,
8 | // output .d.ts declaration files for consumers
9 | "declaration": true,
10 | // output .js.map sourcemap files for consumers
11 | "sourceMap": true,
12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index
13 | "rootDir": "./src",
14 | // stricter type-checking for stronger correctness. Recommended by TS
15 | "strict": true,
16 | // linter checks for common issues
17 | "noImplicitReturns": true,
18 | "noFallthroughCasesInSwitch": true,
19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | // use Node's module resolution algorithm, instead of the legacy TS one
23 | "moduleResolution": "node",
24 | // transpile JSX to React.createElement
25 | "jsx": "react",
26 | // interop between ESM and CJS modules. Recommended by TS
27 | "esModuleInterop": true,
28 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
29 | "skipLibCheck": true,
30 | // error out if import and file system have a casing mismatch. Recommended by TS
31 | "forceConsistentCasingInFileNames": true,
32 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
33 | "noEmit": true,
34 | "resolveJsonModule": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/packages/variants/.gitignore:
--------------------------------------------------------------------------------
1 | *.log
2 | .DS_Store
3 | node_modules
4 | dist
--------------------------------------------------------------------------------
/packages/variants/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @css-picons/variants
2 |
3 | ## 0.0.5
4 |
5 | ### Patch Changes
6 |
7 | - Updated dependencies [b599663]
8 | - @css-picons/types@0.0.5
9 |
10 | ## 0.0.4
11 |
12 | ### Patch Changes
13 |
14 | - 6892674: - Add transform method for mutating icon svgs.
15 | - Add more ways of loading icons.
16 | - Updated dependencies [6892674]
17 | - @css-picons/types@0.0.4
18 |
19 | ## 0.0.3
20 |
21 | ### Patch Changes
22 |
23 | - 377f0a2: Merge custom collections into `collections` key
24 | - Updated dependencies [377f0a2]
25 | - Updated dependencies [98f601d]
26 | - @css-picons/types@0.0.3
27 |
28 | ## 0.0.2
29 |
30 | ### Patch Changes
31 |
32 | - b613efd: Allow custom collection
33 | - 75e99ce: Bump packages
34 | - Updated dependencies [b613efd]
35 | - Updated dependencies [75e99ce]
36 | - @css-picons/types@0.0.2
37 |
38 | ## 0.0.1
39 |
40 | ### Patch Changes
41 |
42 | - c9c44db: Initial release
43 | - Updated dependencies [c9c44db]
44 | - @css-picons/types@0.0.1
45 |
--------------------------------------------------------------------------------
/packages/variants/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@css-picons/variants",
3 | "version": "0.0.5",
4 | "license": "MIT",
5 | "description": "Pure CSS icons for css panda",
6 | "main": "dist/index.js",
7 | "module": "dist/index.mjs",
8 | "types": "dist/index.d.ts",
9 | "author": "Abraham - anubra266 ",
10 | "scripts": {
11 | "build": "tsup src/index.ts --format=cjs,esm --shims --dts",
12 | "dev": "pnpm build --watch",
13 | "test": "echo \"Error: no test specified\""
14 | },
15 | "files": [
16 | "dist"
17 | ],
18 | "sideEffects": false,
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "dependencies": {
23 | "@css-picons/types": "workspace:*",
24 | "@iconify/utils": "^2.1.4"
25 | }
26 | }
--------------------------------------------------------------------------------
/packages/variants/src/create-svg.ts:
--------------------------------------------------------------------------------
1 | import { IconifyIcon, iconToSVG, replaceIDs } from '@iconify/utils'
2 |
3 | export function createSvg(iconData: IconifyIcon) {
4 | const svgData = iconToSVG(iconData)
5 | const svgAttributes: Record = {
6 | xmlns: 'http://www.w3.org/2000/svg',
7 | 'xmlns:xlink': 'http://www.w3.org/1999/xlink',
8 | ...svgData.attributes,
9 | }
10 |
11 | const svgAttributesStr = Object.keys(svgAttributes)
12 | .map(
13 | (attr) =>
14 | // No need to check attributes for special characters, such as quotes,
15 | // they cannot contain anything that needs escaping.
16 | `${attr}="${svgAttributes[attr as keyof typeof svgAttributes]}"`,
17 | )
18 | .join(' ')
19 |
20 | const svg = ``
21 |
22 | return svg
23 | }
24 |
--------------------------------------------------------------------------------
/packages/variants/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { CssPiconsOptions } from '@css-picons/types'
2 | import { encodeSvgForCss } from '@iconify/utils'
3 | import { resolveIcons } from './resolve-icons'
4 |
5 | export const getNameVariants = async ({ collections, transform, mode = 'auto' }: CssPiconsOptions) => {
6 | const collectionsMap = await Promise.all(collections.map(resolveIcons))
7 | return collectionsMap.flat().reduce((acc, nxt) => {
8 | if (!nxt.svg) return { ...acc }
9 | const name = `${nxt.collection}:${nxt.icon}` as string
10 | const maskModeName = `${name}?mask`
11 | const bgModeName = `${name}?bg`
12 |
13 | const svg = transform?.(nxt.svg, nxt.collection, nxt.icon) ?? nxt.svg
14 | const { styles, maskStyles, backgroundStyles } = buildVariants(svg, mode)
15 |
16 | return Object.assign(acc, {
17 | [name]: styles,
18 | [maskModeName]: maskStyles,
19 | [bgModeName]: backgroundStyles,
20 | })
21 | }, {})
22 | }
23 |
24 | function buildVariants(svg: string, mode: CssPiconsOptions['mode']) {
25 | const uri = `url("data:image/svg+xml;utf8,${encodeSvgForCss(svg)}")`
26 |
27 | const _mode = mode === 'auto' ? (svg.includes('currentColor') ? 'mask' : 'bg') : mode
28 |
29 | const maskStyles = {
30 | mask: `${uri} no-repeat`,
31 | maskSize: '100% 100%',
32 | backgroundColor: 'currentColor',
33 | // for Safari https://github.com/elk-zone/elk/pull/264
34 | color: 'inherit',
35 | }
36 |
37 | const backgroundStyles = {
38 | background: `${uri} no-repeat`,
39 | backgroundSize: '100% 100%',
40 | backgroundColor: 'transparent',
41 | }
42 |
43 | const styles =
44 | _mode === 'mask'
45 | ? // monochrome
46 | maskStyles
47 | : // colored
48 | backgroundStyles
49 |
50 | return { styles, maskStyles, backgroundStyles }
51 | }
52 |
--------------------------------------------------------------------------------
/packages/variants/src/resolve-icons/index.ts:
--------------------------------------------------------------------------------
1 | import { Collection, CollectionIcon } from '@css-picons/types'
2 | import { resolveCollectionString } from './resolve-collection-string'
3 | import { resolveCollectionObject } from './resolve-collection-object'
4 | import { resolveCollectionFunction } from './resolve-collection-function'
5 |
6 | export async function resolveIcons(collection: Collection): Promise {
7 | if (typeof collection === 'string') {
8 | return await resolveCollectionString(collection)
9 | }
10 |
11 | const [collectionName, collectionData] = collection
12 |
13 | //* Handle collection strings
14 | if (typeof collectionData === 'string') {
15 | return await resolveCollectionString(collectionData, collectionName)
16 | }
17 |
18 | //* Handle functions
19 | if (isFunction(collectionData)) {
20 | return await resolveCollectionFunction(collectionData, collectionName)
21 | }
22 |
23 | //* Handle objects - iconifyJSON or customiconset
24 | return await resolveCollectionObject(collectionData, collectionName)
25 | }
26 |
27 | const isFunction = (v: any): v is Function => typeof v === 'function'
28 |
--------------------------------------------------------------------------------
/packages/variants/src/resolve-icons/resolve-collection-function.ts:
--------------------------------------------------------------------------------
1 | import { CollectionIcon, CustomIconFunction } from '@css-picons/types'
2 | import { resolveCollectionString } from './resolve-collection-string'
3 | import { resolveCollectionObject } from './resolve-collection-object'
4 |
5 | export async function resolveCollectionFunction(
6 | collectionDataFunction: CustomIconFunction,
7 | collectionName: string,
8 | ): Promise {
9 | const collectionData = await collectionDataFunction()
10 |
11 | if (typeof collectionData === 'string') {
12 | return await resolveCollectionString(collectionData, collectionName)
13 | }
14 | return await resolveCollectionObject(collectionData, collectionName)
15 | }
16 |
--------------------------------------------------------------------------------
/packages/variants/src/resolve-icons/resolve-collection-object.ts:
--------------------------------------------------------------------------------
1 | import { CollectionIcon, CustomIconRecord, IconifyJSON } from '@css-picons/types'
2 | import { validateIconSet } from '@iconify/utils'
3 | import { resolveIconEntries } from './resolve-icon-entries'
4 |
5 | export async function resolveCollectionObject(
6 | collectionData: CustomIconRecord,
7 | collectionName: string,
8 | ): Promise {
9 | //* Check if it's Iconfiy iconsJSON
10 | if (isIconifyJSON(collectionData)) {
11 | return resolveIconEntries(collectionName, collectionData)
12 | }
13 |
14 | //* When it's a custom icon set
15 | return await Promise.all(
16 | Object.entries(collectionData).map(async ([icon, iconData]) => {
17 | return {
18 | collection: collectionName,
19 | icon,
20 | svg: typeof iconData === 'string' ? iconData : await iconData(),
21 | }
22 | }),
23 | )
24 | }
25 |
26 | const isIconifyJSON = (v: any): v is IconifyJSON => {
27 | try {
28 | const iconJSON = validateIconSet(v)
29 | return !!iconJSON
30 | } catch (error) {
31 | return false
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/packages/variants/src/resolve-icons/resolve-collection-string.ts:
--------------------------------------------------------------------------------
1 | import { CollectionIcon } from '@css-picons/types'
2 | import { resolveIconEntries } from './resolve-icon-entries'
3 |
4 | export async function resolveCollectionString(
5 | collection: string,
6 | collectionName: string = collection,
7 | ): Promise {
8 | try {
9 | const path = `@iconify-json/${collection}/icons.json`
10 |
11 | return resolveIconPath(collectionName, path)
12 | } catch (error) {
13 | try {
14 | const path = `@iconify/json/json/${collection}.json`
15 |
16 | return resolveIconPath(collectionName, path)
17 | } catch (error) {
18 | console.log(
19 | '\x1b[31m',
20 | `You provided ${collection} as an icon collection in your panda config. You must install the ${`@iconify-json/${collection}`} package or to get all icons; install the @iconify/json package`,
21 | )
22 | process.exit(1)
23 | }
24 | }
25 | }
26 |
27 | function resolveIconPath(collection: string, path: string) {
28 | const iconsJson = require(path)
29 | return resolveIconEntries(collection, iconsJson)
30 | }
31 |
--------------------------------------------------------------------------------
/packages/variants/src/resolve-icons/resolve-icon-entries.ts:
--------------------------------------------------------------------------------
1 | import { CollectionIcon, IconifyJSON } from '@css-picons/types'
2 | import { getIconData } from '@iconify/utils'
3 | import { createSvg } from '../create-svg'
4 |
5 | export function resolveIconEntries(collectionName: string, iconObj: IconifyJSON): CollectionIcon[] {
6 | const collectionIconEntries = Object.keys(iconObj.icons)
7 | return collectionIconEntries.map((icon) => {
8 | const iconData = getIconData(iconObj, icon)
9 | const svg = iconData ? createSvg(iconData) : null
10 | return { collection: collectionName, icon, svg }
11 | })
12 | }
13 |
--------------------------------------------------------------------------------
/packages/variants/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs
3 | "include": ["src", "types"],
4 | "compilerOptions": {
5 | "module": "esnext",
6 | "lib": ["dom", "esnext"],
7 | "importHelpers": false,
8 | // output .d.ts declaration files for consumers
9 | "declaration": true,
10 | // output .js.map sourcemap files for consumers
11 | "sourceMap": true,
12 | // match output dir to input dir. e.g. dist/index instead of dist/src/index
13 | "rootDir": "./src",
14 | // stricter type-checking for stronger correctness. Recommended by TS
15 | "strict": true,
16 | // linter checks for common issues
17 | "noImplicitReturns": true,
18 | "noFallthroughCasesInSwitch": true,
19 | // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | // use Node's module resolution algorithm, instead of the legacy TS one
23 | "moduleResolution": "node",
24 | // transpile JSX to React.createElement
25 | "jsx": "react",
26 | // interop between ESM and CJS modules. Recommended by TS
27 | "esModuleInterop": true,
28 | // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS
29 | "skipLibCheck": true,
30 | // error out if import and file system have a casing mismatch. Recommended by TS
31 | "forceConsistentCasingInFileNames": true,
32 | // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc`
33 | "noEmit": true,
34 | "resolveJsonModule": true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | # pnpm-workspace.yaml
2 | packages:
3 | - 'packages/*'
4 | - 'site'
5 |
--------------------------------------------------------------------------------
/site/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | ## Panda
27 | styled-system
28 |
--------------------------------------------------------------------------------
/site/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | CSS Picons Demo
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/site/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sandbox-vite",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "prepare": "panda",
8 | "dev": "vite",
9 | "build": "tsc && vite build",
10 | "preview": "vite preview",
11 | "css": "PANDA_DEBUG=ast:* panda",
12 | "css:gen": "PANDA_DEBUG=* panda codegen",
13 | "css:dev": "PANDA_DEBUG=file:* panda --watch"
14 | },
15 | "dependencies": {
16 | "@iconify-json/carbon": "^1.1.16",
17 | "@iconify-json/fe": "^1.1.6",
18 | "@iconify-json/ph": "^1.1.5",
19 | "node-fetch": "^3.3.1",
20 | "react": "^18.2.0",
21 | "react-dom": "^18.2.0"
22 | },
23 | "devDependencies": {
24 | "@css-picons/config": "workspace:*",
25 | "@iconify-json/cryptocurrency-color": "^1.1.3",
26 | "@iconify-json/mdi": "^1.1.52",
27 | "@pandacss/dev": "dev",
28 | "@types/react": "18.2.6",
29 | "@types/react-dom": "18.2.4",
30 | "@vitejs/plugin-react": "4.0.0",
31 | "postcss": "8.4.23",
32 | "typescript": "5.0.4",
33 | "vite": "4.3.5"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/site/panda.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from '@pandacss/dev'
2 | import { cssPicons } from '@css-picons/config'
3 | import feIconsData from '@iconify-json/fe/icons.json'
4 | import phIconsData from '@iconify-json/ph/icons.json'
5 | import fs from 'node:fs'
6 | import fetch from 'node-fetch'
7 |
8 | const iconPreset = cssPicons({
9 | collections: [
10 | 'mdi',
11 | 'cryptocurrency-color',
12 | [
13 | 'custom',
14 | {
15 | circle: '',
16 | vite: () => fs.readFileSync('./public/vite.svg', { encoding: 'utf-8' }),
17 | },
18 | ],
19 | [
20 | 'local',
21 | //* Load all svgs in a directory
22 | () => {
23 | const files = fs.readdirSync('./public')
24 | const svgFiles = files.filter((n) => n.endsWith('.svg'))
25 | if (!svgFiles.length) console.error('No SVG files in path')
26 | const iconSet = svgFiles.reduce(
27 | async (acc, nxt) =>
28 | Object.assign(acc, { [nxt.split('.svg')[0]]: fs.readFileSync(`./public/${nxt}`, { encoding: 'utf-8' }) }),
29 | {},
30 | )
31 | return iconSet
32 | },
33 | ],
34 | [
35 | 'solar',
36 | {
37 | 'airbuds-outline': async () => {
38 | //* fetch icon svg from a remote server:
39 | // ! We use node-fetch package because we can't access the native fetch
40 | return await fetch('https://api.iconify.design/solar:airbuds-outline.svg?color=%23888888').then((res) =>
41 | res.text(),
42 | )
43 | },
44 | },
45 | ],
46 | ['fe', feIconsData],
47 | ['carbon', () => import('@iconify-json/carbon/icons.json').then((i) => i.default as any)],
48 | ['ph', () => phIconsData],
49 | [
50 | 'circle-flags',
51 | async () => {
52 | //* fetch iconifyJson from a remote server:
53 | //! We use node-fetch package because we can't access the native fetch
54 | return await fetch('https://raw.githubusercontent.com/iconify/icon-sets/master/json/circle-flags.json').then(
55 | (res) => res.json(),
56 | )
57 | },
58 | ],
59 | ],
60 |
61 | transform(svg, collection, icon) {
62 | // ! Put a working sample
63 | // do not apply fill to this icons on this collection
64 | if (collection === 'circle-flags' && icon === 'ng') return svg
65 | return svg.replace(/#fff/, 'currentColor')
66 | },
67 |
68 | styles: {
69 | verticalAlign: 'middle',
70 | display: 'inline-block',
71 | },
72 | })
73 |
74 | export default defineConfig({
75 | presets: ['@pandacss/dev/presets', iconPreset],
76 | preflight: true,
77 | include: ['./src/**/*.{tsx,ts}'],
78 | outdir: 'styled-system',
79 | jsxFramework: 'react',
80 | })
81 |
--------------------------------------------------------------------------------
/site/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | '@pandacss/dev/postcss': {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/site/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/site/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { css, cx } from '../styled-system/css'
2 | import { flex, stack } from '../styled-system/patterns'
3 | import { icon, IconVariantProps } from '../styled-system/recipes'
4 | import { SystemStyleObject } from '../styled-system/types'
5 |
6 | type IconProps = IconVariantProps & SystemStyleObject
7 | function Icon({ name, ...rest }: IconProps) {
8 | return (
9 |
18 | )
19 | }
20 |
21 | function App() {
22 | return (
23 |
24 | mdi:account-alert-outline
25 |
26 |
27 | mdi:alpha-e (color: red.400)
28 |
29 | cryptocurrency-color:aave
30 |
31 |
32 | custom:circle
33 |
34 | custom:vite
35 |
36 | loal:vite
37 |
38 | solar:airbuds-outline
39 |
40 | fe:check-verified
41 |
42 | carbon:build-tool
43 |
44 | ph:alien
45 |
46 | circle-flags:ng
47 |
48 |
49 | )
50 | }
51 |
52 | export default App
53 |
--------------------------------------------------------------------------------
/site/src/index.css:
--------------------------------------------------------------------------------
1 | @layer reset, base, tokens, recipes, utilities;
2 |
--------------------------------------------------------------------------------
/site/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')!).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/site/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/site/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/site/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | base: './',
7 | plugins: [react()],
8 | build: {
9 | outDir: 'dist_site',
10 | },
11 | })
12 |
--------------------------------------------------------------------------------