mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-16 20:27:43 +01:00
Improve formatting (#1814)
* Ignore linting for examples in docs * Formatting JSX single attribute per line * Separte `format` and `lint:format` in package.json * Bump prettier version * Run format
This commit is contained in:
@@ -6,6 +6,5 @@ tests
|
|||||||
node_modules
|
node_modules
|
||||||
.eslintrc.js
|
.eslintrc.js
|
||||||
docs/images
|
docs/images
|
||||||
docs/guide/basics/examples
|
docs/**/examples/
|
||||||
docs/guide/advanced/examples
|
|
||||||
packages/lucide-react/dynamicIconImports.js
|
packages/lucide-react/dynamicIconImports.js
|
||||||
|
|||||||
13
.eslintrc.js
13
.eslintrc.js
@@ -42,12 +42,15 @@ module.exports = {
|
|||||||
'@html-eslint/no-duplicate-attrs': 'error',
|
'@html-eslint/no-duplicate-attrs': 'error',
|
||||||
'@html-eslint/no-inline-styles': 'error',
|
'@html-eslint/no-inline-styles': 'error',
|
||||||
'@html-eslint/require-attrs': [
|
'@html-eslint/require-attrs': [
|
||||||
'error',
|
'error',
|
||||||
...Object.entries(DEFAULT_ATTRS)
|
...Object.entries(DEFAULT_ATTRS).map(([attr, value]) => ({
|
||||||
.map(([attr, value]) => ({ tag: 'svg', attr, value: String(value) }))
|
tag: 'svg',
|
||||||
|
attr,
|
||||||
|
value: String(value),
|
||||||
|
})),
|
||||||
],
|
],
|
||||||
'@html-eslint/indent': ['error', 2],
|
'@html-eslint/indent': ['error', 2],
|
||||||
"@html-eslint/no-multiple-empty-lines": ["error", { "max": 0 }],
|
'@html-eslint/no-multiple-empty-lines': ['error', { max: 0 }],
|
||||||
'@html-eslint/no-extra-spacing-attrs': [
|
'@html-eslint/no-extra-spacing-attrs': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
@@ -64,7 +67,7 @@ module.exports = {
|
|||||||
'@html-eslint/element-newline': 'error',
|
'@html-eslint/element-newline': 'error',
|
||||||
'@html-eslint/no-trailing-spaces': 'error',
|
'@html-eslint/no-trailing-spaces': 'error',
|
||||||
'@html-eslint/quotes': 'error',
|
'@html-eslint/quotes': 'error',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
6
.github/actions/build-and-test.yml
vendored
6
.github/actions/build-and-test.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
name: "Build and Test"
|
name: 'Build and Test'
|
||||||
description: "Builds and test a package"
|
description: 'Builds and test a package'
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
@@ -7,7 +7,7 @@ inputs:
|
|||||||
required: true
|
required: true
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: 'composite'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
|
|||||||
6
.github/actions/check-icons.yml
vendored
6
.github/actions/check-icons.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
name: "Check icons"
|
name: 'Check icons'
|
||||||
description: "Cross-checks icon and category references in JSON descriptors"
|
description: 'Cross-checks icon and category references in JSON descriptors'
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
name:
|
name:
|
||||||
@@ -7,7 +7,7 @@ inputs:
|
|||||||
required: true
|
required: true
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: 'composite'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
|
|||||||
96
.github/labeler.yml
vendored
96
.github/labeler.yml
vendored
@@ -1,92 +1,92 @@
|
|||||||
# For changed dependencies
|
# For changed dependencies
|
||||||
📦 dependencies:
|
📦 dependencies:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- pnpm-lock.yaml
|
- pnpm-lock.yaml
|
||||||
|
|
||||||
# For changes in documentation
|
# For changes in documentation
|
||||||
📖 documentation:
|
📖 documentation:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- docs/*.md
|
- docs/*.md
|
||||||
- docs/**/*.md
|
- docs/**/*.md
|
||||||
|
|
||||||
# For changes in the site, but not markdown files
|
# For changes in the site, but not markdown files
|
||||||
🌍 site:
|
🌍 site:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
|
|
||||||
# For changes in the metadata
|
# For changes in the metadata
|
||||||
🫧 metadata:
|
🫧 metadata:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'icons/*.json'
|
- 'icons/*.json'
|
||||||
- categories/*
|
- categories/*
|
||||||
|
|
||||||
# For changes or added icons
|
# For changes or added icons
|
||||||
🎨 icon:
|
🎨 icon:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'icons/*.svg'
|
- 'icons/*.svg'
|
||||||
|
|
||||||
# For changes in the lucide package
|
# For changes in the lucide package
|
||||||
🧳 lucide package:
|
🧳 lucide package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide/*'
|
- 'packages/lucide/*'
|
||||||
|
|
||||||
# For changes in the lucide React package
|
# For changes in the lucide React package
|
||||||
⚛️ react package:
|
⚛️ react package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-react/*'
|
- 'packages/lucide-react/*'
|
||||||
|
|
||||||
# For changes in the lucide React Native package
|
# For changes in the lucide React Native package
|
||||||
⚛️ react native package:
|
⚛️ react native package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-react-native/*'
|
- 'packages/lucide-react-native/*'
|
||||||
|
|
||||||
# For changes in the lucide vue packages
|
# For changes in the lucide vue packages
|
||||||
💎 vue package:
|
💎 vue package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-vue/*'
|
- 'packages/lucide-vue/*'
|
||||||
- 'packages/lucide-vue-next/*'
|
- 'packages/lucide-vue-next/*'
|
||||||
|
|
||||||
# For changes in the lucide angular package
|
# For changes in the lucide angular package
|
||||||
🅰️ angular package:
|
🅰️ angular package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-angular/*'
|
- 'packages/lucide-angular/*'
|
||||||
|
|
||||||
# For changes in the lucide preact package
|
# For changes in the lucide preact package
|
||||||
⚛️ preact package:
|
⚛️ preact package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-preact/*'
|
- 'packages/lucide-preact/*'
|
||||||
|
|
||||||
# For changes in the lucide svelte package
|
# For changes in the lucide svelte package
|
||||||
🧣 svelte package:
|
🧣 svelte package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-svelte/*'
|
- 'packages/lucide-svelte/*'
|
||||||
|
|
||||||
# For changes in the lucide solid package
|
# For changes in the lucide solid package
|
||||||
🪝 solid package:
|
🪝 solid package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-solid/*'
|
- 'packages/lucide-solid/*'
|
||||||
|
|
||||||
# For changes in the lucide static package
|
# For changes in the lucide static package
|
||||||
🪨 static package:
|
🪨 static package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-static/*'
|
- 'packages/lucide-static/*'
|
||||||
|
|
||||||
# For changes in the lucide flutter package
|
# For changes in the lucide flutter package
|
||||||
🏹 flutter package:
|
🏹 flutter package:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- 'packages/lucide-flutter/*'
|
- 'packages/lucide-flutter/*'
|
||||||
|
|||||||
2
.github/workflows/close-stale-prs.yml
vendored
2
.github/workflows/close-stale-prs.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
name: Close stale issues and PR
|
name: Close stale issues and PR
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "45 1 * * *"
|
- cron: '45 1 * * *'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
|
|||||||
6
.github/workflows/labeler.yml
vendored
6
.github/workflows/labeler.yml
vendored
@@ -1,6 +1,6 @@
|
|||||||
name: "Pull Request Labeler"
|
name: 'Pull Request Labeler'
|
||||||
on:
|
on:
|
||||||
- pull_request_target
|
- pull_request_target
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
triage:
|
triage:
|
||||||
@@ -9,4 +9,4 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@v5
|
- uses: actions/labeler@v5
|
||||||
|
|||||||
2
.github/workflows/lucide-font.yml
vendored
2
.github/workflows/lucide-font.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
|||||||
- name: Create font in ./lucide-font
|
- name: Create font in ./lucide-font
|
||||||
run: pnpm build:font
|
run: pnpm build:font
|
||||||
|
|
||||||
- name: "Upload to Artifacts"
|
- name: 'Upload to Artifacts'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: lucide-font
|
name: lucide-font
|
||||||
|
|||||||
30
.github/workflows/release.yml
vendored
30
.github/workflows/release.yml
vendored
@@ -41,17 +41,18 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
package: [
|
package:
|
||||||
'lucide',
|
[
|
||||||
'lucide-react',
|
'lucide',
|
||||||
'lucide-react-native',
|
'lucide-react',
|
||||||
'lucide-vue',
|
'lucide-react-native',
|
||||||
'lucide-vue-next',
|
'lucide-vue',
|
||||||
'lucide-angular',
|
'lucide-vue-next',
|
||||||
'lucide-preact',
|
'lucide-angular',
|
||||||
'lucide-solid',
|
'lucide-preact',
|
||||||
'lucide-svelte',
|
'lucide-solid',
|
||||||
]
|
'lucide-svelte',
|
||||||
|
]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v2
|
||||||
@@ -136,7 +137,7 @@ jobs:
|
|||||||
- name: Create font in ./lucide-font
|
- name: Create font in ./lucide-font
|
||||||
run: pnpm build:font
|
run: pnpm build:font
|
||||||
|
|
||||||
- name: "Upload to Artifacts"
|
- name: 'Upload to Artifacts'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: lucide-font
|
name: lucide-font
|
||||||
@@ -145,10 +146,7 @@ jobs:
|
|||||||
post-release:
|
post-release:
|
||||||
if: github.repository == 'lucide-icons/lucide'
|
if: github.repository == 'lucide-icons/lucide'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [
|
needs: [pre-release, lucide-font]
|
||||||
pre-release,
|
|
||||||
lucide-font,
|
|
||||||
]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
|
|
||||||
|
# docs examples
|
||||||
|
docs/**/examples/
|
||||||
|
|
||||||
# lucide-angular
|
# lucide-angular
|
||||||
packages/lucide-angular/.angular/cache
|
packages/lucide-angular/.angular/cache
|
||||||
|
|
||||||
|
|||||||
11
.vscode/settings.json
vendored
11
.vscode/settings.json
vendored
@@ -1,13 +1,6 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": ["devs", "preact", "Preact"],
|
||||||
"devs",
|
|
||||||
"preact",
|
|
||||||
"Preact"
|
|
||||||
],
|
|
||||||
"eslint.enable": true,
|
"eslint.enable": true,
|
||||||
"eslint.validate": [
|
"eslint.validate": ["javascript", "svg"],
|
||||||
"javascript",
|
|
||||||
"svg"
|
|
||||||
],
|
|
||||||
"svg.preview.background": "transparent"
|
"svg.preview.background": "transparent"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { eventHandler, setResponseHeader } from 'h3'
|
import { eventHandler, setResponseHeader } from 'h3';
|
||||||
import iconMetaData from '../../data/iconMetaData'
|
import iconMetaData from '../../data/iconMetaData';
|
||||||
|
|
||||||
export default eventHandler((event) => {
|
export default eventHandler((event) => {
|
||||||
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
|
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
|
||||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
|
||||||
|
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
Object.entries(iconMetaData).map(([name, { categories }]) => [ name, categories ])
|
Object.entries(iconMetaData).map(([name, { categories }]) => [name, categories]),
|
||||||
)
|
);
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ export default eventHandler((event) => {
|
|||||||
backdropString,
|
backdropString,
|
||||||
src,
|
src,
|
||||||
color: name in iconNodes ? 'red' : '#777',
|
color: name in iconNodes ? 'red' : '#777',
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const svg = Buffer.from(
|
const svg = Buffer.from(
|
||||||
// We can't use jsx here, is not supported here by nitro.
|
// We can't use jsx here, is not supported here by nitro.
|
||||||
renderToString(createElement(SvgPreview, { src, showGrid: true }, children))
|
renderToString(createElement(SvgPreview, { src, showGrid: true }, children)),
|
||||||
).toString('utf8');
|
).toString('utf8');
|
||||||
|
|
||||||
defaultContentType(event, 'image/svg+xml');
|
defaultContentType(event, 'image/svg+xml');
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default eventHandler(async (event) => {
|
|||||||
stroke-width="2"
|
stroke-width="2"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
`
|
`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const resvg = new Resvg(svg, { background: '#000' });
|
const resvg = new Resvg(svg, { background: '#000' });
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { eventHandler, setResponseHeader, defaultContentType } from 'h3'
|
import { eventHandler, setResponseHeader, defaultContentType } from 'h3';
|
||||||
import { renderToString } from 'react-dom/server'
|
import { renderToString } from 'react-dom/server';
|
||||||
import { createElement } from 'react'
|
import { createElement } from 'react';
|
||||||
import SvgPreview from '../../../lib/SvgPreview/index.tsx';
|
import SvgPreview from '../../../lib/SvgPreview/index.tsx';
|
||||||
import createLucideIcon, { IconNode } from 'lucide-react/src/createLucideIcon'
|
import createLucideIcon, { IconNode } from 'lucide-react/src/createLucideIcon';
|
||||||
import { parseSync } from 'svgson';
|
import { parseSync } from 'svgson';
|
||||||
|
|
||||||
export default eventHandler((event) => {
|
export default eventHandler((event) => {
|
||||||
const { params } = event.context
|
const { params } = event.context;
|
||||||
|
|
||||||
const [strokeWidth, svgData] = params.data.split('/');
|
const [strokeWidth, svgData] = params.data.split('/');
|
||||||
const data = svgData.slice(0, -4);
|
const data = svgData.slice(0, -4);
|
||||||
@@ -16,8 +16,8 @@ export default eventHandler((event) => {
|
|||||||
const Icon = createLucideIcon(
|
const Icon = createLucideIcon(
|
||||||
'icon',
|
'icon',
|
||||||
parseSync(src.includes('<svg') ? src : `<svg>${src}</svg>`).children.map(
|
parseSync(src.includes('<svg') ? src : `<svg>${src}</svg>`).children.map(
|
||||||
({ name, attributes }) => [name, attributes]
|
({ name, attributes }) => [name, attributes],
|
||||||
) as IconNode
|
) as IconNode,
|
||||||
);
|
);
|
||||||
|
|
||||||
const svg = Buffer.from(
|
const svg = Buffer.from(
|
||||||
@@ -33,12 +33,12 @@ export default eventHandler((event) => {
|
|||||||
@media screen and (prefers-color-scheme: dark) {
|
@media screen and (prefers-color-scheme: dark) {
|
||||||
svg { stroke: #fff; fill: transparent !important; }
|
svg { stroke: #fff; fill: transparent !important; }
|
||||||
}
|
}
|
||||||
</style>`
|
</style>`,
|
||||||
)
|
),
|
||||||
).toString('utf8');
|
).toString('utf8');
|
||||||
|
|
||||||
defaultContentType(event, 'image/svg+xml')
|
defaultContentType(event, 'image/svg+xml');
|
||||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
|
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
|
||||||
|
|
||||||
return svg
|
return svg;
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
import { eventHandler, getQuery, setResponseHeader } from 'h3'
|
import { eventHandler, getQuery, setResponseHeader } from 'h3';
|
||||||
import iconNodes from '../../data/iconNodes'
|
import iconNodes from '../../data/iconNodes';
|
||||||
import { IconNodeWithKeys } from '../../theme/types'
|
import { IconNodeWithKeys } from '../../theme/types';
|
||||||
|
|
||||||
export default eventHandler((event) => {
|
export default eventHandler((event) => {
|
||||||
const query = getQuery(event)
|
const query = getQuery(event);
|
||||||
|
|
||||||
const withUniqueKeys = query.withUniqueKeys === 'true'
|
const withUniqueKeys = query.withUniqueKeys === 'true';
|
||||||
|
|
||||||
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
|
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
|
||||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
|
||||||
|
|
||||||
if (withUniqueKeys) {
|
if (withUniqueKeys) {
|
||||||
return iconNodes
|
return iconNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.entries(iconNodes).reduce((acc, [name, iconNode]) => {
|
return Object.entries(iconNodes).reduce((acc, [name, iconNode]) => {
|
||||||
if (withUniqueKeys) {
|
if (withUniqueKeys) {
|
||||||
return [name, iconNode]
|
return [name, iconNode];
|
||||||
}
|
}
|
||||||
|
|
||||||
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs}]) => {
|
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs }]) => {
|
||||||
return [name, attrs]
|
return [name, attrs];
|
||||||
})
|
});
|
||||||
|
|
||||||
acc[name] = newIconNode
|
acc[name] = newIconNode;
|
||||||
|
|
||||||
return acc
|
return acc;
|
||||||
}, {})
|
}, {});
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
import { eventHandler, getQuery, setResponseHeader, createError } from 'h3'
|
import { eventHandler, getQuery, setResponseHeader, createError } from 'h3';
|
||||||
import iconNodes from '../../data/iconNodes'
|
import iconNodes from '../../data/iconNodes';
|
||||||
import createLucideIcon from 'lucide-react/src/createLucideIcon'
|
import createLucideIcon from 'lucide-react/src/createLucideIcon';
|
||||||
import { renderToString } from 'react-dom/server'
|
import { renderToString } from 'react-dom/server';
|
||||||
import { createElement } from 'react'
|
import { createElement } from 'react';
|
||||||
|
|
||||||
export default eventHandler((event) => {
|
export default eventHandler((event) => {
|
||||||
const { params } = event.context
|
const { params } = event.context;
|
||||||
|
|
||||||
const iconNode = iconNodes[params.iconName]
|
const iconNode = iconNodes[params.iconName];
|
||||||
|
|
||||||
if (iconNode == null) {
|
if (iconNode == null) {
|
||||||
const error = createError({
|
const error = createError({
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
message: `Icon "${params.iconName}" not found`,
|
message: `Icon "${params.iconName}" not found`,
|
||||||
})
|
});
|
||||||
|
|
||||||
return sendError(event, error)
|
return sendError(event, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const width = getQuery(event).width || undefined
|
const width = getQuery(event).width || undefined;
|
||||||
const height = getQuery(event).height || undefined
|
const height = getQuery(event).height || undefined;
|
||||||
const color = getQuery(event).color || undefined
|
const color = getQuery(event).color || undefined;
|
||||||
const strokeWidth = getQuery(event).strokeWidth || undefined
|
const strokeWidth = getQuery(event).strokeWidth || undefined;
|
||||||
|
|
||||||
const LucideIcon = createLucideIcon(params.iconName, iconNode)
|
const LucideIcon = createLucideIcon(params.iconName, iconNode);
|
||||||
|
|
||||||
const svg = Buffer.from(
|
const svg = Buffer.from(
|
||||||
renderToString(
|
renderToString(
|
||||||
@@ -32,14 +32,13 @@ export default eventHandler((event) => {
|
|||||||
height,
|
height,
|
||||||
color: color ? `#${color}` : undefined,
|
color: color ? `#${color}` : undefined,
|
||||||
strokeWidth,
|
strokeWidth,
|
||||||
}
|
}),
|
||||||
))
|
),
|
||||||
).toString('utf8');
|
).toString('utf8');
|
||||||
|
|
||||||
defaultContentType(event, 'image/svg+xml')
|
defaultContentType(event, 'image/svg+xml');
|
||||||
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
|
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
|
||||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
|
||||||
|
|
||||||
return svg
|
return svg;
|
||||||
|
});
|
||||||
})
|
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { eventHandler, setResponseHeader } from 'h3'
|
import { eventHandler, setResponseHeader } from 'h3';
|
||||||
import iconMetaData from '../../data/iconMetaData'
|
import iconMetaData from '../../data/iconMetaData';
|
||||||
|
|
||||||
export default eventHandler((event) => {
|
export default eventHandler((event) => {
|
||||||
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
|
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
|
||||||
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
|
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
|
||||||
|
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(Object.entries(iconMetaData).map(([name, { tags }]) => [name, tags]));
|
||||||
Object.entries(iconMetaData).map(([name, { tags }]) => [ name, tags ])
|
});
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export default eventHandler(() => {
|
export default eventHandler(() => {
|
||||||
return { nitro: 'Is Awesome! asda' }
|
return { nitro: 'Is Awesome! asda' };
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { fileURLToPath, URL } from 'node:url'
|
import { fileURLToPath, URL } from 'node:url';
|
||||||
import { defineConfig } from 'vitepress'
|
import { defineConfig } from 'vitepress';
|
||||||
import sidebar from './sidebar';
|
import sidebar from './sidebar';
|
||||||
|
|
||||||
const title = "Lucide";
|
const title = 'Lucide';
|
||||||
const socialTitle = "Lucide Icons";
|
const socialTitle = 'Lucide Icons';
|
||||||
const description = "Beautiful & consistent icon toolkit made by the community."
|
const description = 'Beautiful & consistent icon toolkit made by the community.';
|
||||||
|
|
||||||
// https://vitepress.dev/reference/site-config
|
// https://vitepress.dev/reference/site-config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -19,86 +19,131 @@ export default defineConfig({
|
|||||||
{
|
{
|
||||||
find: /^.*\/VPIconAlignLeft\.vue$/,
|
find: /^.*\/VPIconAlignLeft\.vue$/,
|
||||||
replacement: fileURLToPath(
|
replacement: fileURLToPath(
|
||||||
new URL('./theme/components/overrides/VPIconAlignLeft.vue', import.meta.url)
|
new URL('./theme/components/overrides/VPIconAlignLeft.vue', import.meta.url),
|
||||||
)
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: /^.*\/VPFooter\.vue$/,
|
find: /^.*\/VPFooter\.vue$/,
|
||||||
replacement: fileURLToPath(
|
replacement: fileURLToPath(
|
||||||
new URL('./theme/components/overrides/VPFooter.vue', import.meta.url)
|
new URL('./theme/components/overrides/VPFooter.vue', import.meta.url),
|
||||||
)
|
),
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
head: [
|
head: [
|
||||||
[ 'script', {
|
[
|
||||||
src: 'https://analytics.lucide.dev/js/script.js',
|
'script',
|
||||||
'data-domain': 'lucide.dev',
|
{
|
||||||
defer: ''
|
src: 'https://analytics.lucide.dev/js/script.js',
|
||||||
}],
|
'data-domain': 'lucide.dev',
|
||||||
[ 'meta', {
|
defer: '',
|
||||||
property:"og:locale",
|
},
|
||||||
content:"en_US"
|
],
|
||||||
}],
|
[
|
||||||
[ 'meta', {
|
'meta',
|
||||||
property:"og:type",
|
{
|
||||||
content:"website"
|
property: 'og:locale',
|
||||||
}],
|
content: 'en_US',
|
||||||
[ 'meta', {
|
},
|
||||||
property:"og:site_name",
|
],
|
||||||
content: title,
|
[
|
||||||
}],
|
'meta',
|
||||||
[ 'meta', {
|
{
|
||||||
property:"og:title",
|
property: 'og:type',
|
||||||
content: socialTitle,
|
content: 'website',
|
||||||
}],
|
},
|
||||||
[ 'meta', {
|
],
|
||||||
property:"og:description",
|
[
|
||||||
content: description
|
'meta',
|
||||||
}],
|
{
|
||||||
[ 'meta', {
|
property: 'og:site_name',
|
||||||
property:"og:url",
|
content: title,
|
||||||
content:"https://lucide.dev"
|
},
|
||||||
}],
|
],
|
||||||
[ 'meta', {
|
[
|
||||||
property:"og:image",
|
'meta',
|
||||||
content: "https://lucide.dev/og.png"
|
{
|
||||||
}],
|
property: 'og:title',
|
||||||
[ 'meta', {
|
content: socialTitle,
|
||||||
property:"og:image:width",
|
},
|
||||||
content:"1200"
|
],
|
||||||
}],
|
[
|
||||||
[ 'meta', {
|
'meta',
|
||||||
property:"og:image:height",
|
{
|
||||||
content:"630"
|
property: 'og:description',
|
||||||
}],
|
content: description,
|
||||||
[ 'meta', {
|
},
|
||||||
property:"og:image:type",
|
],
|
||||||
content:"image/png"
|
[
|
||||||
}],
|
'meta',
|
||||||
[ 'meta', {
|
{
|
||||||
property:"twitter:card",
|
property: 'og:url',
|
||||||
content:"summary_large_image"
|
content: 'https://lucide.dev',
|
||||||
}],
|
},
|
||||||
[ 'meta', {
|
],
|
||||||
property:"twitter:title",
|
[
|
||||||
content: socialTitle,
|
'meta',
|
||||||
}],
|
{
|
||||||
[ 'meta', {
|
property: 'og:image',
|
||||||
property:"twitter:description",
|
content: 'https://lucide.dev/og.png',
|
||||||
content: description
|
},
|
||||||
}],
|
],
|
||||||
[ 'meta', {
|
[
|
||||||
property:"twitter:image",
|
'meta',
|
||||||
content:"https://lucide.dev/og.png"
|
{
|
||||||
}],
|
property: 'og:image:width',
|
||||||
|
content: '1200',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'meta',
|
||||||
|
{
|
||||||
|
property: 'og:image:height',
|
||||||
|
content: '630',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'meta',
|
||||||
|
{
|
||||||
|
property: 'og:image:type',
|
||||||
|
content: 'image/png',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'meta',
|
||||||
|
{
|
||||||
|
property: 'twitter:card',
|
||||||
|
content: 'summary_large_image',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'meta',
|
||||||
|
{
|
||||||
|
property: 'twitter:title',
|
||||||
|
content: socialTitle,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'meta',
|
||||||
|
{
|
||||||
|
property: 'twitter:description',
|
||||||
|
content: description,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'meta',
|
||||||
|
{
|
||||||
|
property: 'twitter:image',
|
||||||
|
content: 'https://lucide.dev/og.png',
|
||||||
|
},
|
||||||
|
],
|
||||||
],
|
],
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
// https://vitepress.dev/reference/default-theme-config
|
// https://vitepress.dev/reference/default-theme-config
|
||||||
logo: {
|
logo: {
|
||||||
light: '/logo.light.svg',
|
light: '/logo.light.svg',
|
||||||
dark: '/logo.dark.svg'
|
dark: '/logo.dark.svg',
|
||||||
},
|
},
|
||||||
nav: [
|
nav: [
|
||||||
{ text: 'Icons', link: '/icons/' },
|
{ text: 'Icons', link: '/icons/' },
|
||||||
@@ -110,21 +155,21 @@ export default defineConfig({
|
|||||||
sidebar,
|
sidebar,
|
||||||
socialLinks: [
|
socialLinks: [
|
||||||
{ icon: 'github', link: 'https://github.com/lucide-icons/lucide' },
|
{ icon: 'github', link: 'https://github.com/lucide-icons/lucide' },
|
||||||
{ icon: 'discord', link: 'https://discord.gg/EH6nSts' }
|
{ icon: 'discord', link: 'https://discord.gg/EH6nSts' },
|
||||||
],
|
],
|
||||||
footer: {
|
footer: {
|
||||||
message: 'Released under the ISC License.',
|
message: 'Released under the ISC License.',
|
||||||
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`
|
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`,
|
||||||
},
|
},
|
||||||
editLink: {
|
editLink: {
|
||||||
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path'
|
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path',
|
||||||
},
|
},
|
||||||
carbonAds: {
|
carbonAds: {
|
||||||
code: 'CWYIC53U',
|
code: 'CWYIC53U',
|
||||||
placement: 'lucidedev'
|
placement: 'lucidedev',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
sitemap: {
|
sitemap: {
|
||||||
hostname: 'https://lucide.dev/'
|
hostname: 'https://lucide.dev/',
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -3,87 +3,171 @@
|
|||||||
"order": 0,
|
"order": 0,
|
||||||
"icon": "js",
|
"icon": "js",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide", "href": "https://www.npmjs.com/package/lucide" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide", "href": "https://www.npmjs.com/package/lucide" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-react": {
|
"lucide-react": {
|
||||||
"order": 1,
|
"order": 1,
|
||||||
"icon": "react",
|
"icon": "react",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-react", "href": "https://www.npmjs.com/package/lucide-react" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-react", "href": "https://www.npmjs.com/package/lucide-react" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-react",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-react"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-react",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-react"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-vue": {
|
"lucide-vue": {
|
||||||
"order": 2,
|
"order": 2,
|
||||||
"icon": "vue",
|
"icon": "vue",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-vue", "href": "https://www.npmjs.com/package/lucide-vue" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-vue", "href": "https://www.npmjs.com/package/lucide-vue" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-vue",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-vue"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-vue",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-vue"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-vue-next": {
|
"lucide-vue-next": {
|
||||||
"order": 3,
|
"order": 3,
|
||||||
"icon": "vue-next",
|
"icon": "vue-next",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-vue-next", "href": "https://www.npmjs.com/package/lucide-vue-next" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-vue-next", "href": "https://www.npmjs.com/package/lucide-vue-next" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-vue-next",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-vue-next"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-vue-next",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-vue-next"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-svelte": {
|
"lucide-svelte": {
|
||||||
"order": 4,
|
"order": 4,
|
||||||
"icon": "svelte",
|
"icon": "svelte",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-svelte", "href": "https://www.npmjs.com/package/lucide-svelte" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-svelte", "href": "https://www.npmjs.com/package/lucide-svelte" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-svelte",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-svelte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-svelte",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-svelte"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-solid": {
|
"lucide-solid": {
|
||||||
"order": 4,
|
"order": 4,
|
||||||
"icon": "solid",
|
"icon": "solid",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-solid", "href": "https://www.npmjs.com/package/lucide-solid" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-solid", "href": "https://www.npmjs.com/package/lucide-solid" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-solid",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-solid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-solid",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-solid"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-preact": {
|
"lucide-preact": {
|
||||||
"order": 5,
|
"order": 5,
|
||||||
"icon": "preact",
|
"icon": "preact",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-preact", "href": "https://www.npmjs.com/package/lucide-preact" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-preact", "href": "https://www.npmjs.com/package/lucide-preact" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-preact",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-preact"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-preact",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-preact"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-react-native": {
|
"lucide-react-native": {
|
||||||
"order": 6,
|
"order": 6,
|
||||||
"icon": "react-native",
|
"icon": "react-native",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-react-native", "href": "https://www.npmjs.com/package/lucide-react-native" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-react-native", "href": "https://www.npmjs.com/package/lucide-react-native" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-react-native",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-react-native"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-react-native",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-react-native"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-angular": {
|
"lucide-angular": {
|
||||||
"order": 7,
|
"order": 7,
|
||||||
"icon": "angular",
|
"icon": "angular",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-angular", "href": "https://www.npmjs.com/package/lucide-angular" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-angular", "href": "https://www.npmjs.com/package/lucide-angular" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-angular",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-angular"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-angular",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-angular"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-static": {
|
"lucide-static": {
|
||||||
"order": 8,
|
"order": 8,
|
||||||
"icon": "svg",
|
"icon": "svg",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/v/lucide-static", "href": "https://www.npmjs.com/package/lucide-static" },
|
{
|
||||||
{ "alt": "npm", "src": "https://img.shields.io/npm/dw/lucide-static", "href": "https://www.npmjs.com/package/lucide-static" }
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/v/lucide-static",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-static"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alt": "npm",
|
||||||
|
"src": "https://img.shields.io/npm/dw/lucide-static",
|
||||||
|
"href": "https://www.npmjs.com/package/lucide-static"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"lucide-flutter": {
|
"lucide-flutter": {
|
||||||
"order": 9,
|
"order": 9,
|
||||||
"icon": "flutter",
|
"icon": "flutter",
|
||||||
"shields": [
|
"shields": [
|
||||||
{ "alt": "flutter", "src": "https://img.shields.io/pub/v/lucide_icons", "href": "https://img.shields.io/pub/v/lucide_icons" }
|
{
|
||||||
|
"alt": "flutter",
|
||||||
|
"src": "https://img.shields.io/pub/v/lucide_icons",
|
||||||
|
"href": "https://img.shields.io/pub/v/lucide_icons"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,21 +17,62 @@ const Backdrop = ({ src, color = 'red', backdropString }: BackdropProps): JSX.El
|
|||||||
patternUnits="userSpaceOnUse"
|
patternUnits="userSpaceOnUse"
|
||||||
patternTransform="rotate(45 50 50)"
|
patternTransform="rotate(45 50 50)"
|
||||||
>
|
>
|
||||||
<line stroke={color} strokeWidth={0.1} y2={1} />
|
<line
|
||||||
<line stroke={color} strokeWidth={0.1} y2={1} />
|
stroke={color}
|
||||||
|
strokeWidth={0.1}
|
||||||
|
y2={1}
|
||||||
|
/>
|
||||||
|
<line
|
||||||
|
stroke={color}
|
||||||
|
strokeWidth={0.1}
|
||||||
|
y2={1}
|
||||||
|
/>
|
||||||
</pattern>
|
</pattern>
|
||||||
</defs>
|
</defs>
|
||||||
<mask id="svg-preview-backdrop-mask-outline" maskUnits="userSpaceOnUse">
|
<mask
|
||||||
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
|
id="svg-preview-backdrop-mask-outline"
|
||||||
<g dangerouslySetInnerHTML={{ __html: src }} strokeWidth={2.05} />
|
maskUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<g
|
||||||
|
stroke="#fff"
|
||||||
|
dangerouslySetInnerHTML={{ __html: backdropString }}
|
||||||
|
/>
|
||||||
|
<g
|
||||||
|
dangerouslySetInnerHTML={{ __html: src }}
|
||||||
|
strokeWidth={2.05}
|
||||||
|
/>
|
||||||
</mask>
|
</mask>
|
||||||
<mask id="svg-preview-backdrop-mask-fill" maskUnits="userSpaceOnUse">
|
<mask
|
||||||
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
|
id="svg-preview-backdrop-mask-fill"
|
||||||
<g dangerouslySetInnerHTML={{ __html: src }} strokeWidth={2.05} />
|
maskUnits="userSpaceOnUse"
|
||||||
<g strokeWidth={1.75} dangerouslySetInnerHTML={{ __html: backdropString }} />
|
>
|
||||||
|
<g
|
||||||
|
stroke="#fff"
|
||||||
|
dangerouslySetInnerHTML={{ __html: backdropString }}
|
||||||
|
/>
|
||||||
|
<g
|
||||||
|
dangerouslySetInnerHTML={{ __html: src }}
|
||||||
|
strokeWidth={2.05}
|
||||||
|
/>
|
||||||
|
<g
|
||||||
|
strokeWidth={1.75}
|
||||||
|
dangerouslySetInnerHTML={{ __html: backdropString }}
|
||||||
|
/>
|
||||||
</mask>
|
</mask>
|
||||||
<g strokeWidth={2.25} stroke="url(#pattern)" mask={'url(#svg-preview-backdrop-mask-outline)'}>
|
<g
|
||||||
<rect x="0" y="0" width="24" height="24" fill="url(#pattern)" opacity={0.5} stroke="none" />
|
strokeWidth={2.25}
|
||||||
|
stroke="url(#pattern)"
|
||||||
|
mask={'url(#svg-preview-backdrop-mask-outline)'}
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fill="url(#pattern)"
|
||||||
|
opacity={0.5}
|
||||||
|
stroke="none"
|
||||||
|
/>
|
||||||
</g>
|
</g>
|
||||||
<rect
|
<rect
|
||||||
x="0"
|
x="0"
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ const Grid = ({
|
|||||||
strokeWidth: number;
|
strokeWidth: number;
|
||||||
radius: number;
|
radius: number;
|
||||||
} & PathProps<'stroke', 'strokeWidth'>) => (
|
} & PathProps<'stroke', 'strokeWidth'>) => (
|
||||||
<g className="svg-preview-grid-group" strokeLinecap="butt" {...props}>
|
<g
|
||||||
|
className="svg-preview-grid-group"
|
||||||
|
strokeLinecap="butt"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
<rect
|
<rect
|
||||||
className="svg-preview-grid-rect"
|
className="svg-preview-grid-rect"
|
||||||
width={24 - props.strokeWidth}
|
width={24 - props.strokeWidth}
|
||||||
@@ -44,15 +48,21 @@ const Shadow = ({
|
|||||||
paths: Path[];
|
paths: Path[];
|
||||||
} & PathProps<'stroke' | 'strokeWidth' | 'strokeOpacity', 'd'>) => {
|
} & PathProps<'stroke' | 'strokeWidth' | 'strokeOpacity', 'd'>) => {
|
||||||
const groupedPaths = Object.entries(
|
const groupedPaths = Object.entries(
|
||||||
paths.reduce((groups, val) => {
|
paths.reduce(
|
||||||
const key = val.c.id;
|
(groups, val) => {
|
||||||
groups[key] = [...(groups[key] || []), val];
|
const key = val.c.id;
|
||||||
return groups;
|
groups[key] = [...(groups[key] || []), val];
|
||||||
}, {} as Record<number, Path[]>)
|
return groups;
|
||||||
|
},
|
||||||
|
{} as Record<number, Path[]>,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<g className="svg-preview-shadow-mask-group" {...props}>
|
<g
|
||||||
|
className="svg-preview-shadow-mask-group"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{groupedPaths.map(([id, paths]) => (
|
{groupedPaths.map(([id, paths]) => (
|
||||||
<mask
|
<mask
|
||||||
id={`svg-preview-shadow-mask-${id}`}
|
id={`svg-preview-shadow-mask-${id}`}
|
||||||
@@ -61,7 +71,15 @@ const Shadow = ({
|
|||||||
strokeWidth={props.strokeWidth}
|
strokeWidth={props.strokeWidth}
|
||||||
stroke="#000"
|
stroke="#000"
|
||||||
>
|
>
|
||||||
<rect x={0} y={0} width={24} height={24} fill="#fff" stroke="none" rx={radius} />
|
<rect
|
||||||
|
x={0}
|
||||||
|
y={0}
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
fill="#fff"
|
||||||
|
stroke="none"
|
||||||
|
rx={radius}
|
||||||
|
/>
|
||||||
<path
|
<path
|
||||||
d={paths
|
d={paths
|
||||||
.flatMap(({ prev, next }) => [
|
.flatMap(({ prev, next }) => [
|
||||||
@@ -74,9 +92,16 @@ const Shadow = ({
|
|||||||
</mask>
|
</mask>
|
||||||
))}
|
))}
|
||||||
</g>
|
</g>
|
||||||
<g className="svg-preview-shadow-group" {...props}>
|
<g
|
||||||
|
className="svg-preview-shadow-group"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{paths.map(({ d, c: { id } }, i) => (
|
{paths.map(({ d, c: { id } }, i) => (
|
||||||
<path key={i} mask={`url(#svg-preview-shadow-mask-${id})`} d={d} />
|
<path
|
||||||
|
key={i}
|
||||||
|
mask={`url(#svg-preview-shadow-mask-${id})`}
|
||||||
|
d={d}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
<path
|
<path
|
||||||
d={paths
|
d={paths
|
||||||
@@ -94,9 +119,16 @@ const ColoredPath = ({
|
|||||||
paths,
|
paths,
|
||||||
...props
|
...props
|
||||||
}: { paths: Path[]; colors: string[] } & PathProps<never, 'd' | 'stroke'>) => (
|
}: { paths: Path[]; colors: string[] } & PathProps<never, 'd' | 'stroke'>) => (
|
||||||
<g className="svg-preview-colored-path-group" {...props}>
|
<g
|
||||||
|
className="svg-preview-colored-path-group"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{paths.map(({ d, c }, i) => (
|
{paths.map(({ d, c }, i) => (
|
||||||
<path key={i} d={d} stroke={colors[(c.name === 'path' ? i : c.id) % colors.length]} />
|
<path
|
||||||
|
key={i}
|
||||||
|
d={d}
|
||||||
|
stroke={colors[(c.name === 'path' ? i : c.id) % colors.length]}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
@@ -138,7 +170,15 @@ const ControlPath = ({
|
|||||||
key={i}
|
key={i}
|
||||||
maskUnits="userSpaceOnUse"
|
maskUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<rect x="0" y="0" width="24" height="24" fill="#fff" stroke="none" rx={radius} />
|
<rect
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
fill="#fff"
|
||||||
|
stroke="none"
|
||||||
|
rx={radius}
|
||||||
|
/>
|
||||||
<path d={`M${prev.x} ${prev.y}h.01`} />
|
<path d={`M${prev.x} ${prev.y}h.01`} />
|
||||||
<path d={`M${next.x} ${next.y}h.01`} />
|
<path d={`M${next.x} ${next.y}h.01`} />
|
||||||
</mask>
|
</mask>
|
||||||
@@ -146,7 +186,10 @@ const ControlPath = ({
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</g>
|
</g>
|
||||||
<g className="svg-preview-control-path-group" {...props}>
|
<g
|
||||||
|
className="svg-preview-control-path-group"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{controlPaths.map(({ d, showMarker }, i) => (
|
{controlPaths.map(({ d, showMarker }, i) => (
|
||||||
<path
|
<path
|
||||||
key={i}
|
key={i}
|
||||||
@@ -155,18 +198,33 @@ const ControlPath = ({
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</g>
|
</g>
|
||||||
<g className="svg-preview-control-path-marker-group" {...props}>
|
<g
|
||||||
|
className="svg-preview-control-path-marker-group"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
<path
|
<path
|
||||||
d={controlPaths
|
d={controlPaths
|
||||||
.flatMap(({ prev, next, showMarker }) =>
|
.flatMap(({ prev, next, showMarker }) =>
|
||||||
showMarker ? [`M${prev.x} ${prev.y}h.01`, `M${next.x} ${next.y}h.01`] : []
|
showMarker ? [`M${prev.x} ${prev.y}h.01`, `M${next.x} ${next.y}h.01`] : [],
|
||||||
)
|
)
|
||||||
.join('')}
|
.join('')}
|
||||||
/>
|
/>
|
||||||
{controlPaths.map(({ d, prev, next, startMarker, endMarker }, i) => (
|
{controlPaths.map(({ d, prev, next, startMarker, endMarker }, i) => (
|
||||||
<React.Fragment key={i}>
|
<React.Fragment key={i}>
|
||||||
{startMarker && <circle cx={prev.x} cy={prev.y} r={pointSize / 2} />}
|
{startMarker && (
|
||||||
{endMarker && <circle cx={next.x} cy={next.y} r={pointSize / 2} />}
|
<circle
|
||||||
|
cx={prev.x}
|
||||||
|
cy={prev.y}
|
||||||
|
r={pointSize / 2}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{endMarker && (
|
||||||
|
<circle
|
||||||
|
cx={next.x}
|
||||||
|
cy={next.y}
|
||||||
|
r={pointSize / 2}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
</g>
|
</g>
|
||||||
@@ -182,15 +240,16 @@ const Radii = ({
|
|||||||
any
|
any
|
||||||
>) => {
|
>) => {
|
||||||
return (
|
return (
|
||||||
<g className="svg-preview-radii-group" {...props}>
|
<g
|
||||||
|
className="svg-preview-radii-group"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{paths.map(
|
{paths.map(
|
||||||
({ c, prev, next, circle }, i) =>
|
({ c, prev, next, circle }, i) =>
|
||||||
circle && (
|
circle && (
|
||||||
<React.Fragment key={i}>
|
<React.Fragment key={i}>
|
||||||
{c.name !== "circle" && (
|
{c.name !== 'circle' && (
|
||||||
<path
|
<path d={`M${prev.x} ${prev.y} ${circle.x} ${circle.y} ${next.x} ${next.y}`} />
|
||||||
d={`M${prev.x} ${prev.y} ${circle.x} ${circle.y} ${next.x} ${next.y}`}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
<circle
|
<circle
|
||||||
cy={circle.y}
|
cy={circle.y}
|
||||||
@@ -200,7 +259,7 @@ const Radii = ({
|
|||||||
stroke={
|
stroke={
|
||||||
(Math.round(circle.x * 100) / 100) % 1 !== 0 ||
|
(Math.round(circle.x * 100) / 100) % 1 !== 0 ||
|
||||||
(Math.round(circle.y * 100) / 100) % 1 !== 0
|
(Math.round(circle.y * 100) / 100) % 1 !== 0
|
||||||
? "red"
|
? 'red'
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -208,11 +267,7 @@ const Radii = ({
|
|||||||
cy={circle.y}
|
cy={circle.y}
|
||||||
cx={circle.x}
|
cx={circle.x}
|
||||||
r={circle.r}
|
r={circle.r}
|
||||||
stroke={
|
stroke={(Math.round(circle.r * 1000) / 1000) % 1 !== 0 ? 'red' : undefined}
|
||||||
(Math.round(circle.r * 1000) / 1000) % 1 !== 0
|
|
||||||
? "red"
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
),
|
),
|
||||||
@@ -230,13 +285,28 @@ const Handles = ({
|
|||||||
>) => {
|
>) => {
|
||||||
console.log(paths);
|
console.log(paths);
|
||||||
return (
|
return (
|
||||||
<g className="svg-preview-handles-group" {...props}>
|
<g
|
||||||
|
className="svg-preview-handles-group"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{paths.map(({ c, prev, next, cp1, cp2 }) => (
|
{paths.map(({ c, prev, next, cp1, cp2 }) => (
|
||||||
<>
|
<>
|
||||||
{cp1 && <path d={`M${prev.x} ${prev.y} ${cp1.x} ${cp1.y}`} />}
|
{cp1 && <path d={`M${prev.x} ${prev.y} ${cp1.x} ${cp1.y}`} />}
|
||||||
{cp1 && <circle cy={cp1.y} cx={cp1.x} r={0.25} />}
|
{cp1 && (
|
||||||
|
<circle
|
||||||
|
cy={cp1.y}
|
||||||
|
cx={cp1.x}
|
||||||
|
r={0.25}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{cp2 && <path d={`M${next.x} ${next.y} ${cp2.x} ${cp2.y}`} />}
|
{cp2 && <path d={`M${next.x} ${next.y} ${cp2.x} ${cp2.y}`} />}
|
||||||
{cp2 && <circle cy={cp2.y} cx={cp2.x} r={0.25} />}
|
{cp2 && (
|
||||||
|
<circle
|
||||||
|
cy={cp2.y}
|
||||||
|
cx={cp2.x}
|
||||||
|
r={0.25}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
</g>
|
</g>
|
||||||
@@ -280,9 +350,27 @@ const SvgPreview = React.forwardRef<
|
|||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<style>{darkModeCss}</style>
|
<style>{darkModeCss}</style>
|
||||||
{showGrid && <Grid strokeWidth={0.1} stroke="#777" strokeOpacity={0.3} radius={1} />}
|
{showGrid && (
|
||||||
<Shadow paths={paths} strokeWidth={4} stroke="#777" radius={1} strokeOpacity={0.15} />
|
<Grid
|
||||||
<Handles paths={paths} strokeWidth={0.12} stroke="#777" strokeOpacity={0.6} />
|
strokeWidth={0.1}
|
||||||
|
stroke="#777"
|
||||||
|
strokeOpacity={0.3}
|
||||||
|
radius={1}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Shadow
|
||||||
|
paths={paths}
|
||||||
|
strokeWidth={4}
|
||||||
|
stroke="#777"
|
||||||
|
radius={1}
|
||||||
|
strokeOpacity={0.15}
|
||||||
|
/>
|
||||||
|
<Handles
|
||||||
|
paths={paths}
|
||||||
|
strokeWidth={0.12}
|
||||||
|
stroke="#777"
|
||||||
|
strokeOpacity={0.6}
|
||||||
|
/>
|
||||||
<ColoredPath
|
<ColoredPath
|
||||||
paths={paths}
|
paths={paths}
|
||||||
colors={[
|
colors={[
|
||||||
@@ -307,8 +395,19 @@ const SvgPreview = React.forwardRef<
|
|||||||
stroke="#777"
|
stroke="#777"
|
||||||
strokeOpacity={0.3}
|
strokeOpacity={0.3}
|
||||||
/>
|
/>
|
||||||
<ControlPath radius={1} paths={paths} pointSize={1} stroke="#fff" strokeWidth={0.125} />
|
<ControlPath
|
||||||
<Handles paths={paths} strokeWidth={0.12} stroke="#FFF" strokeOpacity={0.3} />
|
radius={1}
|
||||||
|
paths={paths}
|
||||||
|
pointSize={1}
|
||||||
|
stroke="#fff"
|
||||||
|
strokeWidth={0.125}
|
||||||
|
/>
|
||||||
|
<Handles
|
||||||
|
paths={paths}
|
||||||
|
strokeWidth={0.12}
|
||||||
|
stroke="#FFF"
|
||||||
|
strokeOpacity={0.3}
|
||||||
|
/>
|
||||||
{children}
|
{children}
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export type Path = {
|
|||||||
|
|
||||||
export type PathProps<
|
export type PathProps<
|
||||||
RequiredProps extends keyof SVGProps<SVGPathElement | SVGRectElement | SVGCircleElement>,
|
RequiredProps extends keyof SVGProps<SVGPathElement | SVGRectElement | SVGCircleElement>,
|
||||||
NeverProps extends keyof SVGProps<SVGPathElement | SVGRectElement | SVGCircleElement>
|
NeverProps extends keyof SVGProps<SVGPathElement | SVGRectElement | SVGCircleElement>,
|
||||||
> = Required<Pick<React.SVGProps<SVGElement & SVGRectElement & SVGCircleElement>, RequiredProps>> &
|
> = Required<Pick<React.SVGProps<SVGElement & SVGRectElement & SVGCircleElement>, RequiredProps>> &
|
||||||
Omit<
|
Omit<
|
||||||
React.SVGProps<SVGPathElement & SVGRectElement & SVGCircleElement>,
|
React.SVGProps<SVGPathElement & SVGRectElement & SVGCircleElement>,
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export const getCommands = (src: string) =>
|
|||||||
getNodes(src)
|
getNodes(src)
|
||||||
.map(convertToPathNode)
|
.map(convertToPathNode)
|
||||||
.flatMap(({ d, name }, idx) =>
|
.flatMap(({ d, name }, idx) =>
|
||||||
new SVGPathData(d).toAbs().commands.map((c, cIdx) => ({ ...c, id: idx, idx: cIdx, name }))
|
new SVGPathData(d).toAbs().commands.map((c, cIdx) => ({ ...c, id: idx, idx: cIdx, name })),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getPaths = (src: string) => {
|
export const getPaths = (src: string) => {
|
||||||
@@ -60,10 +60,10 @@ export const getPaths = (src: string) => {
|
|||||||
let prev: Point | undefined = undefined;
|
let prev: Point | undefined = undefined;
|
||||||
let start: Point | undefined = undefined;
|
let start: Point | undefined = undefined;
|
||||||
const addPath = (
|
const addPath = (
|
||||||
c: typeof commands[number],
|
c: (typeof commands)[number],
|
||||||
next: Point,
|
next: Point,
|
||||||
d?: string,
|
d?: string,
|
||||||
extras?: { circle?: Path['circle']; cp1?: Path['cp1']; cp2?: Path['cp2'] }
|
extras?: { circle?: Path['circle']; cp1?: Path['cp1']; cp2?: Path['cp2'] },
|
||||||
) => {
|
) => {
|
||||||
assert(prev);
|
assert(prev);
|
||||||
paths.push({
|
paths.push({
|
||||||
@@ -153,7 +153,7 @@ export const getPaths = (src: string) => {
|
|||||||
{
|
{
|
||||||
cp1: { x: prev.x - reflectedCp1.x, y: prev.y - reflectedCp1.y },
|
cp1: { x: prev.x - reflectedCp1.x, y: prev.y - reflectedCp1.y },
|
||||||
cp2: { x: c.x2, y: c.y2 },
|
cp2: { x: c.x2, y: c.y2 },
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ export const getPaths = (src: string) => {
|
|||||||
assert(prev);
|
assert(prev);
|
||||||
const backTrackCP = (
|
const backTrackCP = (
|
||||||
index: number,
|
index: number,
|
||||||
currentPoint: { x: number; y: number }
|
currentPoint: { x: number; y: number },
|
||||||
): { x: number; y: number } => {
|
): { x: number; y: number } => {
|
||||||
const previousCommand = commands[index - 1];
|
const previousCommand = commands[index - 1];
|
||||||
if (!previousCommand) {
|
if (!previousCommand) {
|
||||||
@@ -211,7 +211,7 @@ export const getPaths = (src: string) => {
|
|||||||
{
|
{
|
||||||
cp1: { x: prevCP.x, y: prevCP.y },
|
cp1: { x: prevCP.x, y: prevCP.y },
|
||||||
cp2: { x: prevCP.x, y: prevCP.y },
|
cp2: { x: prevCP.x, y: prevCP.y },
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -226,13 +226,13 @@ export const getPaths = (src: string) => {
|
|||||||
c.lArcFlag,
|
c.lArcFlag,
|
||||||
c.sweepFlag,
|
c.sweepFlag,
|
||||||
c.x,
|
c.x,
|
||||||
c.y
|
c.y,
|
||||||
);
|
);
|
||||||
addPath(
|
addPath(
|
||||||
c,
|
c,
|
||||||
c,
|
c,
|
||||||
`M ${prev.x} ${prev.y} A${c.rX} ${c.rY} ${c.xRot} ${c.lArcFlag} ${c.sweepFlag} ${c.x} ${c.y}`,
|
`M ${prev.x} ${prev.y} A${c.rX} ${c.rY} ${c.xRot} ${c.lArcFlag} ${c.sweepFlag} ${c.x} ${c.y}`,
|
||||||
{ circle: c.rX === c.rY ? { ...center, r: c.rX } : undefined }
|
{ circle: c.rX === c.rY ? { ...center, r: c.rX } : undefined },
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ export const arcEllipseCenter = (
|
|||||||
fa: number,
|
fa: number,
|
||||||
fs: number,
|
fs: number,
|
||||||
x2: number,
|
x2: number,
|
||||||
y2: number
|
y2: number,
|
||||||
) => {
|
) => {
|
||||||
const phi = (a * Math.PI) / 180;
|
const phi = (a * Math.PI) / 180;
|
||||||
|
|
||||||
@@ -280,7 +280,7 @@ export const arcEllipseCenter = (
|
|||||||
sign *
|
sign *
|
||||||
Math.sqrt(
|
Math.sqrt(
|
||||||
Math.max(rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p, 0) /
|
Math.max(rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p, 0) /
|
||||||
(rx * rx * y1p * y1p + ry * ry * x1p * x1p)
|
(rx * rx * y1p * y1p + ry * ry * x1p * x1p),
|
||||||
);
|
);
|
||||||
|
|
||||||
const V2 = [(rx * y1p) / ry, (-ry * x1p) / rx];
|
const V2 = [(rx * y1p) / ry, (-ry * x1p) / rx];
|
||||||
|
|||||||
@@ -1,28 +1,34 @@
|
|||||||
import fs from "fs";
|
import fs from 'fs';
|
||||||
import path from "path";
|
import path from 'path';
|
||||||
import {Category, IconEntity} from "../theme/types";
|
import { Category, IconEntity } from '../theme/types';
|
||||||
|
|
||||||
const directory = path.join(process.cwd(), "../categories");
|
const directory = path.join(process.cwd(), '../categories');
|
||||||
|
|
||||||
export function getAllCategoryFiles(): Category[] {
|
export function getAllCategoryFiles(): Category[] {
|
||||||
const fileNames = fs.readdirSync(directory).filter((file) => path.extname(file) === '.json');
|
const fileNames = fs.readdirSync(directory).filter((file) => path.extname(file) === '.json');
|
||||||
|
|
||||||
return fileNames.map((fileName) => {
|
return fileNames.map((fileName) => {
|
||||||
const name = path.basename(fileName, '.json')
|
const name = path.basename(fileName, '.json');
|
||||||
const fileContent = fs.readFileSync(path.join(directory, fileName), 'utf8')
|
const fileContent = fs.readFileSync(path.join(directory, fileName), 'utf8');
|
||||||
|
|
||||||
const parsedFileContent = JSON.parse(fileContent)
|
const parsedFileContent = JSON.parse(fileContent);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
title: parsedFileContent.title,
|
title: parsedFileContent.title,
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapCategoryIconCount(categories: Category[], icons: { categories: IconEntity['categories'] }[]) {
|
export function mapCategoryIconCount(
|
||||||
|
categories: Category[],
|
||||||
|
icons: { categories: IconEntity['categories'] }[],
|
||||||
|
) {
|
||||||
return categories.map((category) => ({
|
return categories.map((category) => ({
|
||||||
...category,
|
...category,
|
||||||
iconCount: icons.reduce((acc, curr) => (curr.categories.includes(category.name) ? ++acc : acc), 0)
|
iconCount: icons.reduce(
|
||||||
}))
|
(acc, curr) => (curr.categories.includes(category.name) ? ++acc : acc),
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
import {
|
import { bundledLanguages, type ThemeRegistration } from 'shikiji';
|
||||||
bundledLanguages,
|
import { getHighlighter } from 'shikiji';
|
||||||
type ThemeRegistration
|
|
||||||
} from 'shikiji'
|
|
||||||
import {
|
|
||||||
getHighlighter,
|
|
||||||
} from 'shikiji'
|
|
||||||
|
|
||||||
|
|
||||||
type CodeExampleType = {
|
type CodeExampleType = {
|
||||||
title: string,
|
title: string;
|
||||||
language: string,
|
language: string;
|
||||||
code: string,
|
code: string;
|
||||||
}[]
|
}[];
|
||||||
|
|
||||||
const getIconCodes = (): CodeExampleType => {
|
const getIconCodes = (): CodeExampleType => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
language: 'html',
|
language: 'html',
|
||||||
title: 'HTML',
|
title: 'HTML',
|
||||||
code: `<i data-lucide="Name"></i>`
|
code: `<i data-lucide="Name"></i>`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
language: 'tsx',
|
language: 'tsx',
|
||||||
@@ -109,36 +103,37 @@ import { LucideAngularModule, PascalCase } from 'lucide-angular';
|
|||||||
|
|
||||||
<div class="icon-Name"></div>
|
<div class="icon-Name"></div>
|
||||||
`,
|
`,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ThemeOptions =
|
export type ThemeOptions =
|
||||||
| ThemeRegistration
|
| ThemeRegistration
|
||||||
| { light: ThemeRegistration; dark: ThemeRegistration }
|
| { light: ThemeRegistration; dark: ThemeRegistration };
|
||||||
|
|
||||||
const highLightCode = async (code: string, lang: string, active?: boolean) => {
|
const highLightCode = async (code: string, lang: string, active?: boolean) => {
|
||||||
const highlighter = await getHighlighter({
|
const highlighter = await getHighlighter({
|
||||||
themes: ['github-light', 'github-dark'],
|
themes: ['github-light', 'github-dark'],
|
||||||
langs: Object.keys(bundledLanguages)
|
langs: Object.keys(bundledLanguages),
|
||||||
})
|
});
|
||||||
|
|
||||||
const highlightedCode = highlighter.codeToHtml(code, {
|
const highlightedCode = highlighter
|
||||||
lang,
|
.codeToHtml(code, {
|
||||||
themes: {
|
lang,
|
||||||
light: 'github-light',
|
themes: {
|
||||||
dark: 'github-dark'
|
light: 'github-light',
|
||||||
},
|
dark: 'github-dark',
|
||||||
defaultColor: false
|
},
|
||||||
}).replace('shiki-themes', 'shiki-themes vp-code')
|
defaultColor: false,
|
||||||
|
})
|
||||||
|
.replace('shiki-themes', 'shiki-themes vp-code');
|
||||||
|
|
||||||
return `<div class="language-${lang} ${active ? 'active' : ''}">
|
return `<div class="language-${lang} ${active ? 'active' : ''}">
|
||||||
<button title="Copy Code" class="copy"></button>
|
<button title="Copy Code" class="copy"></button>
|
||||||
<span class="lang">${lang}</span>
|
<span class="lang">${lang}</span>
|
||||||
${highlightedCode}
|
${highlightedCode}
|
||||||
</div>`
|
</div>`;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
export default async function createCodeExamples() {
|
export default async function createCodeExamples() {
|
||||||
const codes = getIconCodes();
|
const codes = getIconCodes();
|
||||||
@@ -153,7 +148,7 @@ export default async function createCodeExamples() {
|
|||||||
language: language,
|
language: language,
|
||||||
code: codeString,
|
code: codeString,
|
||||||
};
|
};
|
||||||
})
|
});
|
||||||
|
|
||||||
return Promise.all(codeExamplePromises);
|
return Promise.all(codeExamplePromises);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,42 @@
|
|||||||
import { promises as fs, constants } from 'fs';
|
import { promises as fs, constants } from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import yaml from 'js-yaml'
|
import yaml from 'js-yaml';
|
||||||
import { PackageItem } from '../theme/types';
|
import { PackageItem } from '../theme/types';
|
||||||
|
|
||||||
const fileExist = (filePath) => fs.access(filePath, constants.F_OK).then(() => true).catch(() => false)
|
const fileExist = (filePath) =>
|
||||||
|
fs
|
||||||
|
.access(filePath, constants.F_OK)
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
|
||||||
const fetchPackages = async (): Promise<PackageItem[]> => {
|
const fetchPackages = async (): Promise<PackageItem[]> => {
|
||||||
const docsDir = path.resolve(process.cwd(), '../packages');
|
const docsDir = path.resolve(process.cwd(), '../packages');
|
||||||
const fileNames = await (await fs.readdir(docsDir)).map(filename => ({filename, directory: docsDir}))
|
const fileNames = await (
|
||||||
|
await fs.readdir(docsDir)
|
||||||
|
).map((filename) => ({ filename, directory: docsDir }));
|
||||||
|
|
||||||
const packageJsons = await Promise.all(fileNames.map( async ({filename, directory}) => {
|
const packageJsons = await Promise.all(
|
||||||
const filePath = path.resolve(directory, filename)
|
fileNames.map(async ({ filename, directory }) => {
|
||||||
const fileStat = await fs.lstat(filePath);
|
const filePath = path.resolve(directory, filename);
|
||||||
|
const fileStat = await fs.lstat(filePath);
|
||||||
|
|
||||||
if(!fileStat.isDirectory()) return null;
|
if (!fileStat.isDirectory()) return null;
|
||||||
|
|
||||||
const jsonFilePath = path.resolve(filePath, 'package.json')
|
const jsonFilePath = path.resolve(filePath, 'package.json');
|
||||||
if (await fileExist(jsonFilePath)) {
|
if (await fileExist(jsonFilePath)) {
|
||||||
return JSON.parse(
|
return JSON.parse(await fs.readFile(jsonFilePath, 'utf-8'));
|
||||||
await fs.readFile(jsonFilePath, 'utf-8')
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ymlFilePath = path.resolve(filePath, 'pubspec.yaml')
|
const ymlFilePath = path.resolve(filePath, 'pubspec.yaml');
|
||||||
if(await fileExist(ymlFilePath)) {
|
if (await fileExist(ymlFilePath)) {
|
||||||
return yaml.load(
|
return yaml.load(await fs.readFile(ymlFilePath, 'utf-8'));
|
||||||
await fs.readFile(ymlFilePath, 'utf-8')
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
return null;
|
||||||
}))
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return packageJsons
|
return packageJsons;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default fetchPackages;
|
export default fetchPackages;
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
export type IconContent = [icon: string, src:string];
|
export type IconContent = [icon: string, src: string];
|
||||||
|
|
||||||
async function generateZip(icons: IconContent[]) {
|
async function generateZip(icons: IconContent[]) {
|
||||||
const JSZip = (await import('jszip')).default
|
const JSZip = (await import('jszip')).default;
|
||||||
|
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|
||||||
const addingZipPromises = icons.map(([name, src]) =>
|
const addingZipPromises = icons.map(([name, src]) => zip.file(`${name}.svg`, src));
|
||||||
zip.file(`${name}.svg`, src),
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all(addingZipPromises)
|
await Promise.all(addingZipPromises);
|
||||||
|
|
||||||
return zip.generateAsync({ type: 'blob' });
|
return zip.generateAsync({ type: 'blob' });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default generateZip
|
export default generateZip;
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import { createLucideIcon } from "lucide-react/src/lucide-react"
|
import { createLucideIcon } from 'lucide-react/src/lucide-react';
|
||||||
import { type LucideProps, type IconNode } from "lucide-react/src/createLucideIcon"
|
import { type LucideProps, type IconNode } from 'lucide-react/src/createLucideIcon';
|
||||||
import { IconEntity } from "../theme/types"
|
import { IconEntity } from '../theme/types';
|
||||||
import { renderToStaticMarkup } from 'react-dom/server';
|
import { renderToStaticMarkup } from 'react-dom/server';
|
||||||
import { IconContent } from "./generateZip";
|
import { IconContent } from './generateZip';
|
||||||
|
|
||||||
const getFallbackZip = (icons: IconEntity[], params: LucideProps) => {
|
const getFallbackZip = (icons: IconEntity[], params: LucideProps) => {
|
||||||
return icons
|
return icons.map<IconContent>((icon) => {
|
||||||
.map<IconContent>((icon) => {
|
const Icon = createLucideIcon(icon.name, icon.iconNode as IconNode);
|
||||||
const Icon = createLucideIcon(icon.name, icon.iconNode as IconNode)
|
const src = renderToStaticMarkup(<Icon {...params} />);
|
||||||
const src = renderToStaticMarkup(<Icon {...params} />)
|
return [icon.name, src];
|
||||||
return [icon.name, src]
|
});
|
||||||
})
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
export default getFallbackZip;
|
||||||
export default getFallbackZip
|
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
import fs from "fs";
|
import fs from 'fs';
|
||||||
import path from "path";
|
import path from 'path';
|
||||||
import { IconNodeWithKeys } from "../theme/types";
|
import { IconNodeWithKeys } from '../theme/types';
|
||||||
import iconNodes from '../data/iconNodes'
|
import iconNodes from '../data/iconNodes';
|
||||||
import releaseMeta from "../data/releaseMetaData.json";
|
import releaseMeta from '../data/releaseMetaData.json';
|
||||||
|
|
||||||
const DATE_OF_FORK = '2020-06-08T16:39:52+0100';
|
const DATE_OF_FORK = '2020-06-08T16:39:52+0100';
|
||||||
|
|
||||||
const directory = path.join(process.cwd(), "../icons");
|
const directory = path.join(process.cwd(), '../icons');
|
||||||
|
|
||||||
export interface GetDataOptions {
|
export interface GetDataOptions {
|
||||||
withChildKeys?: boolean
|
withChildKeys?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getData(name: string) {
|
export async function getData(name: string) {
|
||||||
const jsonPath = path.join(directory, `${name}.json`);
|
const jsonPath = path.join(directory, `${name}.json`);
|
||||||
const jsonContent = fs.readFileSync(jsonPath, "utf8");
|
const jsonContent = fs.readFileSync(jsonPath, 'utf8');
|
||||||
const { tags, categories, contributors } = JSON.parse(jsonContent);
|
const { tags, categories, contributors } = JSON.parse(jsonContent);
|
||||||
|
|
||||||
const iconNode = iconNodes[name]
|
const iconNode = iconNodes[name];
|
||||||
|
|
||||||
const releaseData = releaseMeta?.[name] ?? {
|
const releaseData = releaseMeta?.[name] ?? {
|
||||||
"createdRelease": {
|
createdRelease: {
|
||||||
"version": "0.0.0",
|
version: '0.0.0',
|
||||||
"date": DATE_OF_FORK
|
date: DATE_OF_FORK,
|
||||||
},
|
},
|
||||||
"changedRelease": {
|
changedRelease: {
|
||||||
"version": "0.0.0",
|
version: '0.0.0',
|
||||||
"date": DATE_OF_FORK
|
date: DATE_OF_FORK,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
@@ -36,11 +36,11 @@ export async function getData(name: string) {
|
|||||||
categories,
|
categories,
|
||||||
iconNode,
|
iconNode,
|
||||||
contributors,
|
contributors,
|
||||||
...releaseData
|
...releaseData,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllData(): Promise<{ name: string, iconNode: IconNodeWithKeys}[]> {
|
export async function getAllData(): Promise<{ name: string; iconNode: IconNodeWithKeys }[]> {
|
||||||
const names = Object.keys(iconNodes);
|
const names = Object.keys(iconNodes);
|
||||||
|
|
||||||
return Promise.all(names.map((name) => getData(name)));
|
return Promise.all(names.map((name) => getData(name)));
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
import { DefaultTheme, UserConfig } from "vitepress"
|
import { DefaultTheme, UserConfig } from 'vitepress';
|
||||||
|
|
||||||
const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
||||||
'guide':[
|
guide: [
|
||||||
{
|
{
|
||||||
text: 'Introduction',
|
text: 'Introduction',
|
||||||
items: [
|
items: [
|
||||||
{ text: 'What is lucide?', link: '/guide/' },
|
{ text: 'What is lucide?', link: '/guide/' },
|
||||||
{ text: 'Installation', link: '/guide/installation' },
|
{ text: 'Installation', link: '/guide/installation' },
|
||||||
{ text: 'Comparison', link: '/guide/comparison' }
|
{ text: 'Comparison', link: '/guide/comparison' },
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Basics',
|
text: 'Basics',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
text: 'Color',
|
text: 'Color',
|
||||||
link: '/guide/basics/color'
|
link: '/guide/basics/color',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Sizing',
|
text: 'Sizing',
|
||||||
link: '/guide/basics/sizing'
|
link: '/guide/basics/sizing',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Stroke width',
|
text: 'Stroke width',
|
||||||
link: '/guide/basics/stroke-width'
|
link: '/guide/basics/stroke-width',
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
// TODO: Add this section
|
// TODO: Add this section
|
||||||
{
|
{
|
||||||
@@ -37,14 +37,14 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
|||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
text: 'Global styling',
|
text: 'Global styling',
|
||||||
link: '/guide/advanced/global-styling'
|
link: '/guide/advanced/global-styling',
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// text: 'Animations',
|
// text: 'Animations',
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
text: 'Filled icons',
|
text: 'Filled icons',
|
||||||
link: '/guide/advanced/filled-icons'
|
link: '/guide/advanced/filled-icons',
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// text: 'Combining icons',
|
// text: 'Combining icons',
|
||||||
@@ -55,75 +55,73 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
|
|||||||
// {
|
// {
|
||||||
// text: 'Auto importing'
|
// text: 'Auto importing'
|
||||||
// },
|
// },
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Packages',
|
text: 'Packages',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
text: 'Lucide',
|
text: 'Lucide',
|
||||||
link: '/guide/packages/lucide'
|
link: '/guide/packages/lucide',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide React',
|
text: 'Lucide React',
|
||||||
link: '/guide/packages/lucide-react'
|
link: '/guide/packages/lucide-react',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide React Native',
|
text: 'Lucide React Native',
|
||||||
link: '/guide/packages/lucide-react-native'
|
link: '/guide/packages/lucide-react-native',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Vue',
|
text: 'Lucide Vue',
|
||||||
link: '/guide/packages/lucide-vue-next'
|
link: '/guide/packages/lucide-vue-next',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Svelte',
|
text: 'Lucide Svelte',
|
||||||
link: '/guide/packages/lucide-svelte'
|
link: '/guide/packages/lucide-svelte',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Solid',
|
text: 'Lucide Solid',
|
||||||
link: '/guide/packages/lucide-solid'
|
link: '/guide/packages/lucide-solid',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Preact',
|
text: 'Lucide Preact',
|
||||||
link: '/guide/packages/lucide-preact'
|
link: '/guide/packages/lucide-preact',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Angular',
|
text: 'Lucide Angular',
|
||||||
link: '/guide/packages/lucide-angular'
|
link: '/guide/packages/lucide-angular',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Lucide Static',
|
text: 'Lucide Static',
|
||||||
link: '/guide/packages/lucide-static'
|
link: '/guide/packages/lucide-static',
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Contributing',
|
text: 'Contributing',
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
text: 'Icon Design Principles',
|
text: 'Icon Design Principles',
|
||||||
link: '/guide/design/icon-design-guide'
|
link: '/guide/design/icon-design-guide',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Designing in Illustrator',
|
text: 'Designing in Illustrator',
|
||||||
link: '/guide/design/illustrator-guide'
|
link: '/guide/design/illustrator-guide',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Designing in InkScape',
|
text: 'Designing in InkScape',
|
||||||
link: '/guide/design/inkscape-guide'
|
link: '/guide/design/inkscape-guide',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Designing in Figma',
|
text: 'Designing in Figma',
|
||||||
link: '/guide/design/figma-guide'
|
link: '/guide/design/figma-guide',
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// This should be here to keep the sidebar shown on the icons page
|
// This should be here to keep the sidebar shown on the icons page
|
||||||
'icons': [
|
icons: [{ text: '', link: '/' }],
|
||||||
{ text: '', link: '/' },
|
};
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
export default sidebar
|
export default sidebar;
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
export default {
|
export default {
|
||||||
async load() {
|
async load() {
|
||||||
const version = await fetch('https://api.github.com/repos/lucide-icons/lucide/releases/latest').then(res => {
|
const version = await fetch('https://api.github.com/repos/lucide-icons/lucide/releases/latest')
|
||||||
if (res.ok) {
|
.then((res) => {
|
||||||
const releaseData = res.json() as Promise<{ tag_name: string }>
|
if (res.ok) {
|
||||||
|
const releaseData = res.json() as Promise<{ tag_name: string }>;
|
||||||
|
|
||||||
return releaseData
|
return releaseData;
|
||||||
}
|
}
|
||||||
return null
|
return null;
|
||||||
}).then(res => res.tag_name)
|
})
|
||||||
|
.then((res) => res.tag_name);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
version
|
version,
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
import iconNodes from '../../../data/iconNodes'
|
import iconNodes from '../../../data/iconNodes';
|
||||||
|
|
||||||
const getRandomItem = <Item>(items: Item[]): Item => items[Math.floor(Math.random()*items.length)];
|
const getRandomItem = <Item>(items: Item[]): Item =>
|
||||||
|
items[Math.floor(Math.random() * items.length)];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async load() {
|
async load() {
|
||||||
const icons = Object.entries(iconNodes).map(([name, iconNode]) => ({ name, iconNode }))
|
const icons = Object.entries(iconNodes).map(([name, iconNode]) => ({ name, iconNode }));
|
||||||
|
|
||||||
const randomIcons = Array.from({ length: 200 }, () => getRandomItem(icons))
|
const randomIcons = Array.from({ length: 200 }, () => getRandomItem(icons));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
icons: randomIcons,
|
icons: randomIcons,
|
||||||
iconsCount: icons.length,
|
iconsCount: icons.length,
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default {
|
|||||||
logo: '/framework-logos/flutter.svg',
|
logo: '/framework-logos/flutter.svg',
|
||||||
label: 'Lucide documentation for Flutter',
|
label: 'Lucide documentation for Flutter',
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { getAllData } from '../../../lib/icons';
|
import { getAllData } from '../../../lib/icons';
|
||||||
import { getAllCategoryFiles, mapCategoryIconCount } from '../../../lib/categories';
|
import { getAllCategoryFiles, mapCategoryIconCount } from '../../../lib/categories';
|
||||||
import iconsMetaData from '../../../data/iconMetaData'
|
import iconsMetaData from '../../../data/iconMetaData';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async load() {
|
async load() {
|
||||||
let categories = getAllCategoryFiles()
|
let categories = getAllCategoryFiles();
|
||||||
|
|
||||||
categories = mapCategoryIconCount(categories, Object.values(iconsMetaData))
|
categories = mapCategoryIconCount(categories, Object.values(iconsMetaData));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
categories,
|
categories,
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
.confetti-button:before,
|
.confetti-button:before,
|
||||||
.confetti-button:after {
|
.confetti-button:after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: "";
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
width: 140%;
|
width: 140%;
|
||||||
max-width: 160px;
|
max-width: 160px;
|
||||||
@@ -41,8 +41,16 @@
|
|||||||
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
||||||
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
||||||
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%);
|
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%);
|
||||||
background-size: 10% 10%, 20% 20%, 15% 15%, 20% 20%, 18% 18%, 10% 10%, 15% 15%,
|
background-size:
|
||||||
10% 10%, 18% 18%;
|
10% 10%,
|
||||||
|
20% 20%,
|
||||||
|
15% 15%,
|
||||||
|
20% 20%,
|
||||||
|
18% 18%,
|
||||||
|
10% 10%,
|
||||||
|
15% 15%,
|
||||||
|
10% 10%,
|
||||||
|
18% 18%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confetti-button:after {
|
.confetti-button:after {
|
||||||
@@ -55,7 +63,14 @@
|
|||||||
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
||||||
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%),
|
||||||
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%);
|
radial-gradient(circle, var(--confetti-color) 20%, transparent 20%);
|
||||||
background-size: 15% 15%, 20% 20%, 18% 18%, 20% 20%, 15% 15%, 10% 10%, 20% 20%;
|
background-size:
|
||||||
|
15% 15%,
|
||||||
|
20% 20%,
|
||||||
|
18% 18%,
|
||||||
|
20% 20%,
|
||||||
|
15% 15%,
|
||||||
|
10% 10%,
|
||||||
|
20% 20%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.confetti-button.animate:before {
|
.confetti-button.animate:before {
|
||||||
@@ -70,35 +85,89 @@
|
|||||||
@keyframes topBubbles {
|
@keyframes topBubbles {
|
||||||
0% {
|
0% {
|
||||||
color: rgb(var(--text-color) / 0);
|
color: rgb(var(--text-color) / 0);
|
||||||
background-position: 5% 90%, 10% 90%, 10% 90%, 15% 90%, 25% 90%, 25% 90%,
|
background-position:
|
||||||
40% 90%, 55% 90%, 70% 90%;
|
5% 90%,
|
||||||
|
10% 90%,
|
||||||
|
10% 90%,
|
||||||
|
15% 90%,
|
||||||
|
25% 90%,
|
||||||
|
25% 90%,
|
||||||
|
40% 90%,
|
||||||
|
55% 90%,
|
||||||
|
70% 90%;
|
||||||
}
|
}
|
||||||
30% {
|
30% {
|
||||||
color: rgb(var(--text-color) / 1);
|
color: rgb(var(--text-color) / 1);
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
background-position: 0% 80%, 0% 20%, 10% 40%, 20% 0%, 30% 30%, 22% 50%,
|
background-position:
|
||||||
50% 50%, 65% 20%, 90% 30%;
|
0% 80%,
|
||||||
|
0% 20%,
|
||||||
|
10% 40%,
|
||||||
|
20% 0%,
|
||||||
|
30% 30%,
|
||||||
|
22% 50%,
|
||||||
|
50% 50%,
|
||||||
|
65% 20%,
|
||||||
|
90% 30%;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
background-position: 0% 70%, 0% 10%, 10% 30%, 20% -10%, 30% 20%, 22% 40%,
|
background-position:
|
||||||
50% 40%, 65% 10%, 90% 20%;
|
0% 70%,
|
||||||
background-size: 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%;
|
0% 10%,
|
||||||
|
10% 30%,
|
||||||
|
20% -10%,
|
||||||
|
30% 20%,
|
||||||
|
22% 40%,
|
||||||
|
50% 40%,
|
||||||
|
65% 10%,
|
||||||
|
90% 20%;
|
||||||
|
background-size:
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%;
|
||||||
color: rgb(var(--text-color) / 0);
|
color: rgb(var(--text-color) / 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes bottomBubbles {
|
@keyframes bottomBubbles {
|
||||||
0% {
|
0% {
|
||||||
background-position: 10% -10%, 30% 10%, 55% -10%, 70% -10%, 85% -10%,
|
background-position:
|
||||||
70% -10%, 70% 0%;
|
10% -10%,
|
||||||
|
30% 10%,
|
||||||
|
55% -10%,
|
||||||
|
70% -10%,
|
||||||
|
85% -10%,
|
||||||
|
70% -10%,
|
||||||
|
70% 0%;
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
background-position: 0% 80%, 20% 80%, 45% 60%, 60% 100%, 75% 70%, 95% 60%,
|
background-position:
|
||||||
|
0% 80%,
|
||||||
|
20% 80%,
|
||||||
|
45% 60%,
|
||||||
|
60% 100%,
|
||||||
|
75% 70%,
|
||||||
|
95% 60%,
|
||||||
105% 0%;
|
105% 0%;
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
background-position: 0% 90%, 20% 90%, 45% 70%, 60% 110%, 75% 80%, 95% 70%,
|
background-position:
|
||||||
|
0% 90%,
|
||||||
|
20% 90%,
|
||||||
|
45% 70%,
|
||||||
|
60% 110%,
|
||||||
|
75% 80%,
|
||||||
|
95% 70%,
|
||||||
110% 10%;
|
110% 10%;
|
||||||
background-size: 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%;
|
background-size:
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%,
|
||||||
|
0% 0%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import packageData from '../../../data/packageData.json';
|
import packageData from '../../../data/packageData.json';
|
||||||
import thirdPartyPackages from '../../../data/packageData.thirdParty.json';
|
import thirdPartyPackages from '../../../data/packageData.thirdParty.json';
|
||||||
import fetchPackages from "../../../lib/fetchPackages";
|
import fetchPackages from '../../../lib/fetchPackages';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async load() {
|
async load() {
|
||||||
const packages = await fetchPackages();
|
const packages = await fetchPackages();
|
||||||
return {
|
return {
|
||||||
packages: packages
|
packages: packages
|
||||||
.filter(p => p.name in packageData)
|
.filter((p) => p.name in packageData)
|
||||||
.map((pData) => ({
|
.map((pData) => ({
|
||||||
...pData,
|
...pData,
|
||||||
...packageData[pData.name],
|
...packageData[pData.name],
|
||||||
documentation: `/guide/packages/${pData.name}`,
|
documentation: `/guide/packages/${pData.name}`,
|
||||||
source: `https://github.com/lucide-icons/lucide/tree/main/packages/${pData.name}`,
|
source: `https://github.com/lucide-icons/lucide/tree/main/packages/${pData.name}`,
|
||||||
icon: `/framework-logos/${packageData[pData.name].icon}.svg`,
|
icon: `/framework-logos/${packageData[pData.name].icon}.svg`,
|
||||||
})).sort((a, b) => a.order - b.order),
|
}))
|
||||||
|
.sort((a, b) => a.order - b.order),
|
||||||
thirdPartyPackages,
|
thirdPartyPackages,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,69 +1,68 @@
|
|||||||
import { onMounted, onUpdated, onUnmounted } from 'vue';
|
import { onMounted, onUpdated, onUnmounted } from 'vue';
|
||||||
import { throttleAndDebounce } from 'vitepress/dist/client/theme-default/support/utils'
|
import { throttleAndDebounce } from 'vitepress/dist/client/theme-default/support/utils';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is compied and adjusted from vitepress/dist/client/theme-default/composables/useActiveAnchor.ts
|
* This file is compied and adjusted from vitepress/dist/client/theme-default/composables/useActiveAnchor.ts
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function useActiveAnchor(container, marker) {
|
export function useActiveAnchor(container, marker) {
|
||||||
const onScroll = throttleAndDebounce(setActiveLink, 100);
|
const onScroll = throttleAndDebounce(setActiveLink, 100);
|
||||||
let prevActiveLink = null;
|
let prevActiveLink = null;
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
requestAnimationFrame(setActiveLink);
|
requestAnimationFrame(setActiveLink);
|
||||||
window.addEventListener('scroll', onScroll);
|
window.addEventListener('scroll', onScroll);
|
||||||
});
|
});
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
// sidebar update means a route change
|
// sidebar update means a route change
|
||||||
activateLink(location.hash);
|
activateLink(location.hash);
|
||||||
});
|
});
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('scroll', onScroll);
|
window.removeEventListener('scroll', onScroll);
|
||||||
});
|
});
|
||||||
function setActiveLink() {
|
function setActiveLink() {
|
||||||
const links = [].slice.call(container.value.querySelectorAll('.outline-link'));
|
const links = [].slice.call(container.value.querySelectorAll('.outline-link'));
|
||||||
const anchors = [].slice
|
const anchors = [].slice
|
||||||
.call(document.querySelectorAll('.content .header-anchor'))
|
.call(document.querySelectorAll('.content .header-anchor'))
|
||||||
.filter((anchor) => {
|
.filter((anchor) => {
|
||||||
return links.some((link) => {
|
return links.some((link) => {
|
||||||
return link.hash === anchor.hash && anchor.offsetParent !== null;
|
return link.hash === anchor.hash && anchor.offsetParent !== null;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const scrollY = window.scrollY;
|
const scrollY = window.scrollY;
|
||||||
const innerHeight = window.innerHeight;
|
const innerHeight = window.innerHeight;
|
||||||
const offsetHeight = document.body.offsetHeight;
|
const offsetHeight = document.body.offsetHeight;
|
||||||
const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1;
|
const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1;
|
||||||
// page bottom - highlight last one
|
// page bottom - highlight last one
|
||||||
if (anchors.length && isBottom) {
|
if (anchors.length && isBottom) {
|
||||||
activateLink(anchors[anchors.length - 1].hash);
|
activateLink(anchors[anchors.length - 1].hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < anchors.length; i++) {
|
for (let i = 0; i < anchors.length; i++) {
|
||||||
const anchor = anchors[i];
|
const anchor = anchors[i];
|
||||||
const nextAnchor = anchors[i + 1];
|
const nextAnchor = anchors[i + 1];
|
||||||
const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor);
|
const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor);
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
activateLink(hash);
|
activateLink(hash);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function activateLink(hash) {
|
function activateLink(hash) {
|
||||||
if (prevActiveLink) {
|
if (prevActiveLink) {
|
||||||
prevActiveLink.classList.remove('active');
|
prevActiveLink.classList.remove('active');
|
||||||
}
|
}
|
||||||
if (hash !== null) {
|
if (hash !== null) {
|
||||||
prevActiveLink = container.value.querySelector(`a[href="${decodeURIComponent(hash)}"]`);
|
prevActiveLink = container.value.querySelector(`a[href="${decodeURIComponent(hash)}"]`);
|
||||||
}
|
}
|
||||||
const activeLink = prevActiveLink;
|
const activeLink = prevActiveLink;
|
||||||
if (activeLink) {
|
if (activeLink) {
|
||||||
activeLink.classList.add('active');
|
activeLink.classList.add('active');
|
||||||
marker.value.style.top = activeLink.offsetTop + 5 + 'px';
|
marker.value.style.top = activeLink.offsetTop + 5 + 'px';
|
||||||
marker.value.style.opacity = '1';
|
marker.value.style.opacity = '1';
|
||||||
}
|
} else {
|
||||||
else {
|
marker.value.style.top = '33px';
|
||||||
marker.value.style.top = '33px';
|
marker.value.style.opacity = '0';
|
||||||
marker.value.style.opacity = '0';
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,13 +74,13 @@ function getAnchorTop(anchor) {
|
|||||||
function isAnchorActive(index, anchor, nextAnchor) {
|
function isAnchorActive(index, anchor, nextAnchor) {
|
||||||
const scrollTop = window.scrollY;
|
const scrollTop = window.scrollY;
|
||||||
if (index === 0 && scrollTop === 0) {
|
if (index === 0 && scrollTop === 0) {
|
||||||
return [true, null];
|
return [true, null];
|
||||||
}
|
}
|
||||||
if (scrollTop < getAnchorTop(anchor)) {
|
if (scrollTop < getAnchorTop(anchor)) {
|
||||||
return [false, null];
|
return [false, null];
|
||||||
}
|
}
|
||||||
if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor)) {
|
if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor)) {
|
||||||
return [true, anchor.hash];
|
return [true, anchor.hash];
|
||||||
}
|
}
|
||||||
return [false, null];
|
return [false, null];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import {
|
import { ref, inject, Ref } from 'vue';
|
||||||
ref, inject, Ref
|
|
||||||
} from 'vue';
|
|
||||||
|
|
||||||
export const CATEGORY_VIEW_CONTEXT = Symbol('categoryView');
|
export const CATEGORY_VIEW_CONTEXT = Symbol('categoryView');
|
||||||
|
|
||||||
interface CategoryViewContext {
|
interface CategoryViewContext {
|
||||||
selectedCategory: Ref<string>
|
selectedCategory: Ref<string>;
|
||||||
categoryCounts: Ref<Record<string, number>>
|
categoryCounts: Ref<Record<string, number>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const categoryViewContext = {
|
export const categoryViewContext = {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ref } from "vue";
|
import { ref } from 'vue';
|
||||||
|
|
||||||
export default function useConfetti() {
|
export default function useConfetti() {
|
||||||
const animate = ref(false)
|
const animate = ref(false);
|
||||||
const confettiText = ref('confetti!')
|
const confettiText = ref('confetti!');
|
||||||
|
|
||||||
function confetti() {
|
function confetti() {
|
||||||
animate.value = true;
|
animate.value = true;
|
||||||
@@ -15,6 +15,6 @@ export default function useConfetti() {
|
|||||||
return {
|
return {
|
||||||
animate,
|
animate,
|
||||||
confetti,
|
confetti,
|
||||||
confettiText
|
confettiText,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { useFetch } from "@vueuse/core"
|
import { useFetch } from '@vueuse/core';
|
||||||
|
|
||||||
const useFetchCategories = () => useFetch<Record<string, string[]>>(
|
const useFetchCategories = () =>
|
||||||
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/categories`,
|
useFetch<Record<string, string[]>>(
|
||||||
{
|
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/categories`,
|
||||||
immediate:
|
{
|
||||||
typeof window !== 'undefined'
|
immediate:
|
||||||
&& new URLSearchParams(window.location.search).has('search'),
|
typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('search'),
|
||||||
}
|
},
|
||||||
).json()
|
).json();
|
||||||
|
|
||||||
export default useFetchCategories
|
export default useFetchCategories;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { useFetch } from "@vueuse/core"
|
import { useFetch } from '@vueuse/core';
|
||||||
|
|
||||||
const useFetchTags = () => useFetch<Record<string, string[]>>(
|
const useFetchTags = () =>
|
||||||
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/tags`,
|
useFetch<Record<string, string[]>>(
|
||||||
{
|
`${import.meta.env.DEV ? 'http://localhost:3000' : ''}/api/tags`,
|
||||||
immediate:
|
{
|
||||||
typeof window !== 'undefined'
|
immediate:
|
||||||
&& new URLSearchParams(window.location.search).has('search'),
|
typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('search'),
|
||||||
}
|
},
|
||||||
).json()
|
).json();
|
||||||
|
|
||||||
export default useFetchTags
|
export default useFetchTags;
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
import {
|
import { ref, inject, Ref } from 'vue';
|
||||||
ref, inject, Ref
|
|
||||||
} from 'vue';
|
|
||||||
|
|
||||||
export const ICON_STYLE_CONTEXT = Symbol('size');
|
export const ICON_STYLE_CONTEXT = Symbol('size');
|
||||||
|
|
||||||
interface IconSizeContext {
|
interface IconSizeContext {
|
||||||
size: Ref<number>
|
size: Ref<number>;
|
||||||
strokeWidth: Ref<number>
|
strokeWidth: Ref<number>;
|
||||||
color: Ref<string>
|
color: Ref<string>;
|
||||||
absoluteStrokeWidth: Ref<boolean>
|
absoluteStrokeWidth: Ref<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const STYLE_DEFAULTS = {
|
export const STYLE_DEFAULTS = {
|
||||||
@@ -27,7 +25,7 @@ export const iconStyleContext = {
|
|||||||
absoluteStrokeWidth: ref(false),
|
absoluteStrokeWidth: ref(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useIconStyleContext(): IconSizeContext{
|
export function useIconStyleContext(): IconSizeContext {
|
||||||
const context = inject<IconSizeContext>(ICON_STYLE_CONTEXT);
|
const context = inject<IconSizeContext>(ICON_STYLE_CONTEXT);
|
||||||
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
import { shallowRef, computed, Ref } from 'vue';
|
import { shallowRef, computed, Ref } from 'vue';
|
||||||
|
|
||||||
const useSearch = <T>(query: Ref<string>, collection: Ref<T[]>, keys: Fuse.FuseOptionKey<T>[] = []) => {
|
const useSearch = <T>(
|
||||||
|
query: Ref<string>,
|
||||||
|
collection: Ref<T[]>,
|
||||||
|
keys: Fuse.FuseOptionKey<T>[] = [],
|
||||||
|
) => {
|
||||||
const index = shallowRef(
|
const index = shallowRef(
|
||||||
new Fuse(collection.value, {
|
new Fuse(collection.value, {
|
||||||
threshold: 0.2,
|
threshold: 0.2,
|
||||||
keys,
|
keys,
|
||||||
})
|
}),
|
||||||
)
|
);
|
||||||
|
|
||||||
const results = computed(() => {
|
const results = computed(() => {
|
||||||
index.value.setCollection(collection.value);
|
index.value.setCollection(collection.value);
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { h } from 'vue'
|
import { h } from 'vue';
|
||||||
import DefaultTheme from 'vitepress/theme'
|
import DefaultTheme from 'vitepress/theme';
|
||||||
import './style.css'
|
import './style.css';
|
||||||
import { Theme } from 'vitepress'
|
import { Theme } from 'vitepress';
|
||||||
import IconsSidebarNavAfter from './layouts/IconsSidebarNavAfter.vue'
|
import IconsSidebarNavAfter from './layouts/IconsSidebarNavAfter.vue';
|
||||||
import HomeHeroIconsCard from './components/home/HomeHeroIconsCard.vue'
|
import HomeHeroIconsCard from './components/home/HomeHeroIconsCard.vue';
|
||||||
import HomeHeroBefore from "./components/home/HomeHeroBefore.vue";
|
import HomeHeroBefore from './components/home/HomeHeroBefore.vue';
|
||||||
import { ICON_STYLE_CONTEXT, iconStyleContext } from './composables/useIconStyle'
|
import { ICON_STYLE_CONTEXT, iconStyleContext } from './composables/useIconStyle';
|
||||||
import { CATEGORY_VIEW_CONTEXT, categoryViewContext } from './composables/useCategoryView'
|
import { CATEGORY_VIEW_CONTEXT, categoryViewContext } from './composables/useCategoryView';
|
||||||
|
|
||||||
const theme: Partial<Theme> = {
|
const theme: Partial<Theme> = {
|
||||||
extends: DefaultTheme,
|
extends: DefaultTheme,
|
||||||
@@ -15,12 +15,12 @@ const theme: Partial<Theme> = {
|
|||||||
'home-hero-before': () => h(HomeHeroBefore),
|
'home-hero-before': () => h(HomeHeroBefore),
|
||||||
'sidebar-nav-after': () => h(IconsSidebarNavAfter),
|
'sidebar-nav-after': () => h(IconsSidebarNavAfter),
|
||||||
'home-hero-image': () => h(HomeHeroIconsCard),
|
'home-hero-image': () => h(HomeHeroIconsCard),
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
enhanceApp({ app }) {
|
enhanceApp({ app }) {
|
||||||
app.provide(ICON_STYLE_CONTEXT, iconStyleContext)
|
app.provide(ICON_STYLE_CONTEXT, iconStyleContext);
|
||||||
app.provide(CATEGORY_VIEW_CONTEXT, categoryViewContext)
|
app.provide(CATEGORY_VIEW_CONTEXT, categoryViewContext);
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default theme
|
export default theme;
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
:root {
|
:root {
|
||||||
--vp-c-brand: #F56565;
|
--vp-c-brand: #f56565;
|
||||||
--vp-c-brand-light: #F67373;
|
--vp-c-brand-light: #f67373;
|
||||||
--vp-c-brand-lighter: #F89191;
|
--vp-c-brand-lighter: #f89191;
|
||||||
--vp-c-brand-dark: #DC5A5A;
|
--vp-c-brand-dark: #dc5a5a;
|
||||||
--vp-c-brand-darker: #C45050;
|
--vp-c-brand-darker: #c45050;
|
||||||
|
|
||||||
--vp-c-brand-1: #F67373;
|
--vp-c-brand-1: #f67373;
|
||||||
--vp-c-brand-2: #FF7070;
|
--vp-c-brand-2: #ff7070;
|
||||||
--vp-c-brand-3: #F56565;
|
--vp-c-brand-3: #f56565;
|
||||||
--vp-c-brand-4: #DC5A5A;
|
--vp-c-brand-4: #dc5a5a;
|
||||||
--vp-c-brand-5: #C45050;
|
--vp-c-brand-5: #c45050;
|
||||||
|
|
||||||
--vp-c-bg-alt-up: #fff;
|
--vp-c-bg-alt-up: #fff;
|
||||||
--vp-c-bg-alt-down: #fff;
|
--vp-c-bg-alt-down: #fff;
|
||||||
|
|
||||||
--vp-code-editor-plain: #24292E;
|
--vp-code-editor-plain: #24292e;
|
||||||
--vp-code-editor-comment: #6A737D;
|
--vp-code-editor-comment: #6a737d;
|
||||||
--vp-code-editor-keyword: #D73A49;
|
--vp-code-editor-keyword: #d73a49;
|
||||||
--vp-code-editor-tag: #22863A;
|
--vp-code-editor-tag: #22863a;
|
||||||
--vp-code-editor-punctuation: #24292E;
|
--vp-code-editor-punctuation: #24292e;
|
||||||
--vp-code-editor-definition: #6F42C1;
|
--vp-code-editor-definition: #6f42c1;
|
||||||
--vp-code-editor-property: #005CC5;
|
--vp-code-editor-property: #005cc5;
|
||||||
--vp-code-editor-static: #F78C6C;
|
--vp-code-editor-static: #f78c6c;
|
||||||
--vp-code-editor-string: #032F62;
|
--vp-code-editor-string: #032f62;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--vp-c-bg-alt-up: #1B1B1D;
|
--vp-c-bg-alt-up: #1b1b1d;
|
||||||
--vp-c-bg-alt-down: #0F0F10;
|
--vp-c-bg-alt-down: #0f0f10;
|
||||||
|
|
||||||
--vp-code-editor-plain: #E1E4E8;
|
--vp-code-editor-plain: #e1e4e8;
|
||||||
--vp-code-editor-comment: #6A737D;
|
--vp-code-editor-comment: #6a737d;
|
||||||
--vp-code-editor-keyword: #F97583;
|
--vp-code-editor-keyword: #f97583;
|
||||||
--vp-code-editor-tag: #85E89D;
|
--vp-code-editor-tag: #85e89d;
|
||||||
--vp-code-editor-punctuation: #9ECBFF;
|
--vp-code-editor-punctuation: #9ecbff;
|
||||||
--vp-code-editor-definition: #B392F0;
|
--vp-code-editor-definition: #b392f0;
|
||||||
--vp-code-editor-property: #79B8FF;
|
--vp-code-editor-property: #79b8ff;
|
||||||
--vp-code-editor-static: #F78C6C;
|
--vp-code-editor-static: #f78c6c;
|
||||||
--vp-code-editor-string: #9ECBFF;
|
--vp-code-editor-string: #9ecbff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.VPNavBarTitle .logo {
|
.VPNavBarTitle .logo {
|
||||||
@@ -69,7 +69,6 @@
|
|||||||
|
|
||||||
.VPHomeHero .container .main h1.name {
|
.VPHomeHero .container .main h1.name {
|
||||||
color: var(--vp-c-text);
|
color: var(--vp-c-text);
|
||||||
|
|
||||||
}
|
}
|
||||||
.VPHomeHero .container .main h1.name .clip {
|
.VPHomeHero .container .main h1.name .clip {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
@@ -82,7 +81,6 @@
|
|||||||
color: var(--vp-c-brand);
|
color: var(--vp-c-brand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* */
|
/* */
|
||||||
.VPHomeHero .container .image {
|
.VPHomeHero .container .image {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -101,14 +99,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.VPFeature .icon {
|
.VPFeature .icon {
|
||||||
background-color: var(--vp-c-bg);;
|
background-color: var(--vp-c-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.vp-doc[class*=" _icons_"] > div {
|
.vp-doc[class*=' _icons_'] > div {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.VPDoc:has(.vp-doc[class*=" _icons_"]) > .container > .content{
|
.VPDoc:has(.vp-doc[class*=' _icons_']) > .container > .content {
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
@@ -120,7 +118,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 960px) {
|
@media (min-width: 960px) {
|
||||||
|
|
||||||
.VPHomeHero .container .image {
|
.VPHomeHero .container .image {
|
||||||
order: 1;
|
order: 1;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
@@ -141,7 +138,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.VPHomeHero .container .main h1.name {
|
.VPHomeHero .container .main h1.name {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,10 +194,10 @@ html:has(* .outline-link:target) {
|
|||||||
transition: background-color 0.25s;
|
transition: background-color 0.25s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sp-wrapper .sp-tabs .sp-tab-button[data-active="true"] {
|
.sp-wrapper .sp-tabs .sp-tab-button[data-active='true'] {
|
||||||
color: var(--vp-code-tab-active-text-color);
|
color: var(--vp-code-tab-active-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sp-wrapper .sp-tabs .sp-tab-button[data-active="true"]:after {
|
.sp-wrapper .sp-tabs .sp-tab-button[data-active='true']:after {
|
||||||
background-color: var(--vp-code-tab-active-bar-color);
|
background-color: var(--vp-code-tab-active-bar-color);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export type IconNode = [elementName: string, attrs: Record<string, string>][]
|
export type IconNode = [elementName: string, attrs: Record<string, string>][];
|
||||||
export type IconNodeWithKeys = [elementName: string, attrs: Record<string, string>, key: string][]
|
export type IconNodeWithKeys = [elementName: string, attrs: Record<string, string>, key: string][];
|
||||||
|
|
||||||
export interface IconEntity {
|
export interface IconEntity {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -13,45 +13,44 @@ export interface IconEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Category {
|
export interface Category {
|
||||||
name: string
|
name: string;
|
||||||
title: string
|
title: string;
|
||||||
icon?: string
|
icon?: string;
|
||||||
iconCount: number
|
iconCount: number;
|
||||||
icons?: IconEntity[]
|
icons?: IconEntity[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Shield {
|
interface Shield {
|
||||||
alt: string
|
alt: string;
|
||||||
src: string
|
src: string;
|
||||||
href: string
|
href: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PackageItem {
|
export interface PackageItem {
|
||||||
name: string
|
name: string;
|
||||||
description: string
|
description: string;
|
||||||
icon: string
|
icon: string;
|
||||||
iconDark: string
|
iconDark: string;
|
||||||
shields: Shield[]
|
shields: Shield[];
|
||||||
source: string
|
source: string;
|
||||||
documentation: string
|
documentation: string;
|
||||||
order?: number
|
order?: number;
|
||||||
private?: boolean
|
private?: boolean;
|
||||||
flutter?: object
|
flutter?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface Release {
|
export interface Release {
|
||||||
version: string
|
version: string;
|
||||||
date: string
|
date: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ShowcaseItemImage {
|
interface ShowcaseItemImage {
|
||||||
light: string
|
light: string;
|
||||||
dark: string
|
dark: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ShowcaseItem {
|
export interface ShowcaseItem {
|
||||||
name: string
|
name: string;
|
||||||
url: string
|
url: string;
|
||||||
image: ShowcaseItemImage
|
image: ShowcaseItemImage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export default function downloadData(filename:string, data:string) {
|
export default function downloadData(filename: string, data: string) {
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
link.download = filename;
|
link.download = filename;
|
||||||
link.href = data
|
link.href = data;
|
||||||
link.click();
|
link.click();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,26 +9,26 @@ const allowedAttrs = [
|
|||||||
'stroke-linecap',
|
'stroke-linecap',
|
||||||
'stroke-linejoin',
|
'stroke-linejoin',
|
||||||
'class',
|
'class',
|
||||||
]
|
];
|
||||||
|
|
||||||
export default function getSVGIcon(element?: HTMLElement, attrs?: Record<string, string>) {
|
export default function getSVGIcon(element?: HTMLElement, attrs?: Record<string, string>) {
|
||||||
const svg = element ?? document.querySelector('#previewer svg')
|
const svg = element ?? document.querySelector('#previewer svg');
|
||||||
if (!svg) return
|
if (!svg) return;
|
||||||
|
|
||||||
const clonedSvg = svg.cloneNode(true) as SVGElement
|
const clonedSvg = svg.cloneNode(true) as SVGElement;
|
||||||
|
|
||||||
// Filter out attributes that are not allowed in SVGs
|
// Filter out attributes that are not allowed in SVGs
|
||||||
for (const attr of Array.from(clonedSvg.attributes)) {
|
for (const attr of Array.from(clonedSvg.attributes)) {
|
||||||
if (!allowedAttrs.includes(attr.name)) {
|
if (!allowedAttrs.includes(attr.name)) {
|
||||||
clonedSvg.removeAttribute(attr.name)
|
clonedSvg.removeAttribute(attr.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(attrs ?? {})) {
|
for (const [key, value] of Object.entries(attrs ?? {})) {
|
||||||
clonedSvg.setAttribute(key, value)
|
clonedSvg.setAttribute(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const svgString = new XMLSerializer().serializeToString(clonedSvg)
|
const svgString = new XMLSerializer().serializeToString(clonedSvg);
|
||||||
|
|
||||||
return svgString
|
return svgString;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,22 @@
|
|||||||
import relatedIcons from '../.vitepress/data/relatedIcons.json'
|
import relatedIcons from '../.vitepress/data/relatedIcons.json';
|
||||||
import iconNodes from '../.vitepress/data/iconNodes'
|
import iconNodes from '../.vitepress/data/iconNodes';
|
||||||
import * as iconDetails from '../.vitepress/data/iconDetails'
|
import * as iconDetails from '../.vitepress/data/iconDetails';
|
||||||
import { IconEntity } from "../.vitepress/theme/types";
|
import { IconEntity } from '../.vitepress/theme/types';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
paths: async () => {
|
paths: async () => {
|
||||||
return (Object.values(iconDetails) as unknown as IconEntity[]).map((iconEntity) => {
|
return (Object.values(iconDetails) as unknown as IconEntity[]).map((iconEntity) => {
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
...iconEntity,
|
...iconEntity,
|
||||||
relatedIcons: relatedIcons[iconEntity.name].map((name: string) => ({
|
relatedIcons: relatedIcons[iconEntity.name].map((name: string) => ({
|
||||||
name,
|
name,
|
||||||
iconNode: iconNodes[name],
|
iconNode: iconNodes[name],
|
||||||
}))
|
})),
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
params,
|
params,
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { getAllCategoryFiles } from '../.vitepress/lib/categories'
|
import { getAllCategoryFiles } from '../.vitepress/lib/categories';
|
||||||
import iconMetaData from '../.vitepress/data/iconMetaData'
|
import iconMetaData from '../.vitepress/data/iconMetaData';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async load() {
|
async load() {
|
||||||
return {
|
return {
|
||||||
categories: getAllCategoryFiles(),
|
categories: getAllCategoryFiles(),
|
||||||
iconCategories: Object.fromEntries(
|
iconCategories: Object.fromEntries(
|
||||||
Object.entries(iconMetaData).map(([name, { categories }]) => [name, categories])
|
Object.entries(iconMetaData).map(([name, { categories }]) => [name, categories]),
|
||||||
),
|
),
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import createCodeExamples from '../.vitepress/lib/createCodeExamples'
|
import createCodeExamples from '../.vitepress/lib/createCodeExamples';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async load() {
|
async load() {
|
||||||
const codeExamples = await createCodeExamples()
|
const codeExamples = await createCodeExamples();
|
||||||
|
|
||||||
// const randomIcons = Array.from({ length: 200 }, () => getRandomItem(icons))
|
// const randomIcons = Array.from({ length: 200 }, () => getRandomItem(icons))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
codeExamples,
|
codeExamples,
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import iconNodes from '../.vitepress/data/iconNodes'
|
import iconNodes from '../.vitepress/data/iconNodes';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
async load() {
|
async load() {
|
||||||
return {
|
return {
|
||||||
icons: Object.entries(iconNodes).map(([name, iconNode]) => ({ name, iconNode })),
|
icons: Object.entries(iconNodes).map(([name, iconNode]) => ({ name, iconNode })),
|
||||||
}
|
};
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"noEmit": true
|
"noEmit": true,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
"karsa-mistmere",
|
"karsa-mistmere",
|
||||||
"jguddas"
|
"jguddas"
|
||||||
],
|
],
|
||||||
"aliases": ["verified"],
|
"aliases": [
|
||||||
|
"verified"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"verified",
|
"verified",
|
||||||
"check"
|
"check"
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../icon.schema.json",
|
"$schema": "../icon.schema.json",
|
||||||
"contributors": ["danielbayley"],
|
"contributors": [
|
||||||
|
"danielbayley"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"code",
|
"code",
|
||||||
"coding",
|
"coding",
|
||||||
|
|||||||
@@ -4,7 +4,9 @@
|
|||||||
"danielbayley",
|
"danielbayley",
|
||||||
"karsa-mistmere"
|
"karsa-mistmere"
|
||||||
],
|
],
|
||||||
"aliases": ["curly-braces"],
|
"aliases": [
|
||||||
|
"curly-braces"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"json",
|
"json",
|
||||||
"code",
|
"code",
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../icon.schema.json",
|
"$schema": "../icon.schema.json",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"danielbayley"
|
"danielbayley"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"drama",
|
"drama",
|
||||||
"masks",
|
"masks",
|
||||||
"theater",
|
"theater",
|
||||||
"theatre",
|
"theatre",
|
||||||
"entertainment",
|
"entertainment",
|
||||||
"show"
|
"show"
|
||||||
],
|
],
|
||||||
"categories": [
|
"categories": [
|
||||||
"multimedia"
|
"multimedia"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../icon.schema.json",
|
"$schema": "../icon.schema.json",
|
||||||
"contributors": ["danielbayley"],
|
"contributors": [
|
||||||
|
"danielbayley"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"projects",
|
"projects",
|
||||||
"manage",
|
"manage",
|
||||||
@@ -20,5 +22,10 @@
|
|||||||
"code",
|
"code",
|
||||||
"coding"
|
"coding"
|
||||||
],
|
],
|
||||||
"categories": ["charts", "time", "development", "design"]
|
"categories": [
|
||||||
|
"charts",
|
||||||
|
"time",
|
||||||
|
"development",
|
||||||
|
"design"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../icon.schema.json",
|
"$schema": "../icon.schema.json",
|
||||||
"tags": [
|
"tags": [
|
||||||
"flag",
|
"flag",
|
||||||
"bullseye"
|
"bullseye"
|
||||||
],
|
],
|
||||||
"categories": [
|
"categories": [
|
||||||
"gaming"
|
"gaming"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"layout",
|
"layout",
|
||||||
"arrows"
|
"arrows"
|
||||||
],
|
],
|
||||||
"aliases": [
|
"aliases": [
|
||||||
"sidebar-close"
|
"sidebar-close"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"layout",
|
"layout",
|
||||||
"arrows"
|
"arrows"
|
||||||
],
|
],
|
||||||
"aliases": [
|
"aliases": [
|
||||||
"sidebar-open"
|
"sidebar-open"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../icon.schema.json",
|
"$schema": "../icon.schema.json",
|
||||||
"contributors": ["danielbayley"],
|
"contributors": [
|
||||||
|
"danielbayley"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"unshielded",
|
"unshielded",
|
||||||
"cybersecurity",
|
"cybersecurity",
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
"contributors": [
|
"contributors": [
|
||||||
"karsa-mistmere"
|
"karsa-mistmere"
|
||||||
],
|
],
|
||||||
"aliases": ["stars"],
|
"aliases": [
|
||||||
|
"stars"
|
||||||
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"stars",
|
"stars",
|
||||||
"effect",
|
"effect",
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../icon.schema.json",
|
"$schema": "../icon.schema.json",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"danielbayley"
|
"danielbayley"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"theater",
|
"theater",
|
||||||
"theatre",
|
"theatre",
|
||||||
"entertainment",
|
"entertainment",
|
||||||
"podium",
|
"podium",
|
||||||
"stage",
|
"stage",
|
||||||
"musical"
|
"musical"
|
||||||
],
|
],
|
||||||
"categories": [
|
"categories": [
|
||||||
"buildings",
|
"buildings",
|
||||||
"social"
|
"social"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -30,11 +30,12 @@
|
|||||||
"generate:nextJSAliases": "node ./scripts/generateNextJSAliases.mjs",
|
"generate:nextJSAliases": "node ./scripts/generateNextJSAliases.mjs",
|
||||||
"postinstall": "husky install",
|
"postinstall": "husky install",
|
||||||
"lint:es": "eslint .",
|
"lint:es": "eslint .",
|
||||||
"lint:format": "prettier \"**/*.{js,mjs,ts,jsx,tsx,html,css,scss,json,yml,yaml}\" --write",
|
"lint:format": "prettier \"**/*.{js,mjs,ts,jsx,tsx,html,css,scss,json,yml,yaml}\" --check",
|
||||||
"lint:json:icons": "ajv --spec=draft2020 -s icon.schema.json -d 'icons/*.json' > /dev/null",
|
"lint:json:icons": "ajv --spec=draft2020 -s icon.schema.json -d 'icons/*.json' > /dev/null",
|
||||||
"lint:json:categories": "ajv --spec=draft2020 -s category.schema.json -d 'categories/*.json' > /dev/null",
|
"lint:json:categories": "ajv --spec=draft2020 -s category.schema.json -d 'categories/*.json' > /dev/null",
|
||||||
"lint:json": "pnpm run lint:json:icons && pnpm run lint:json:categories",
|
"lint:json": "pnpm run lint:json:icons && pnpm run lint:json:categories",
|
||||||
"lint": "pnpm lint:es && pnpm lint:format && pnpm lint:json",
|
"lint": "pnpm lint:es && pnpm lint:format && pnpm lint:json",
|
||||||
|
"format": "prettier \"**/*.{js,mjs,ts,jsx,tsx,html,css,scss,json,yml,yaml}\" --write",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"gi": "node ./scripts/generate/generateIcons.mjs"
|
"gi": "node ./scripts/generate/generateIcons.mjs"
|
||||||
},
|
},
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
"minimist": "^1.2.8",
|
"minimist": "^1.2.8",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"p-memoize": "^7.1.1",
|
"p-memoize": "^7.1.1",
|
||||||
"prettier": "3.1.1",
|
"prettier": "3.2.4",
|
||||||
"semver": "^7.5.4",
|
"semver": "^7.5.4",
|
||||||
"simple-git": "^3.21.0",
|
"simple-git": "^3.21.0",
|
||||||
"svgo": "^3.1.0",
|
"svgo": "^3.1.0",
|
||||||
|
|||||||
@@ -35,10 +35,7 @@
|
|||||||
"lint": {
|
"lint": {
|
||||||
"builder": "@angular-eslint/builder:lint",
|
"builder": "@angular-eslint/builder:lint",
|
||||||
"options": {
|
"options": {
|
||||||
"lintFilePatterns": [
|
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
||||||
"src/**/*.ts",
|
|
||||||
"src/**/*.html"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
process.env.CHROME_BIN = require('puppeteer').executablePath();
|
process.env.CHROME_BIN = require('puppeteer').executablePath();
|
||||||
|
|
||||||
module.exports = function(config) {
|
module.exports = function (config) {
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
basePath: '',
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
|||||||
@@ -22,5 +22,5 @@ import { LucideIconData } from './types';
|
|||||||
const ${componentName}: LucideIconData = ${JSON.stringify(children)}; //eslint-disable-line no-shadow-restricted-names
|
const ${componentName}: LucideIconData = ${JSON.stringify(children)}; //eslint-disable-line no-shadow-restricted-names
|
||||||
|
|
||||||
export default ${componentName};
|
export default ${componentName};
|
||||||
`
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ describe('LucideAngularComponent', () => {
|
|||||||
testHostComponent.setAbsoluteStrokeWidth(true);
|
testHostComponent.setAbsoluteStrokeWidth(true);
|
||||||
testHostFixture.detectChanges();
|
testHostFixture.detectChanges();
|
||||||
expect(getSvgAttribute('stroke-width')).toBe(
|
expect(getSvgAttribute('stroke-width')).toBe(
|
||||||
formatFixed(strokeWidth / (size / defaultAttributes.height))
|
formatFixed(strokeWidth / (size / defaultAttributes.height)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export class LucideAngularComponent implements OnChanges {
|
|||||||
@Inject(Renderer2) private renderer: Renderer2,
|
@Inject(Renderer2) private renderer: Renderer2,
|
||||||
@Inject(ChangeDetectorRef) private changeDetector: ChangeDetectorRef,
|
@Inject(ChangeDetectorRef) private changeDetector: ChangeDetectorRef,
|
||||||
@Inject(LUCIDE_ICONS) private iconProviders: LucideIconProviderInterface[],
|
@Inject(LUCIDE_ICONS) private iconProviders: LucideIconProviderInterface[],
|
||||||
@Inject(LucideIconConfig) private iconConfig: LucideIconConfig
|
@Inject(LucideIconConfig) private iconConfig: LucideIconConfig,
|
||||||
) {
|
) {
|
||||||
this.defaultSize = defaultAttributes.height;
|
this.defaultSize = defaultAttributes.height;
|
||||||
}
|
}
|
||||||
@@ -99,7 +99,7 @@ export class LucideAngularComponent implements OnChanges {
|
|||||||
this.replaceElement(icoOfName);
|
this.replaceElement(icoOfName);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The "${name}" icon has not been provided by any available icon providers.`
|
`The "${name}" icon has not been provided by any available icon providers.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (Array.isArray(name)) {
|
} else if (Array.isArray(name)) {
|
||||||
@@ -132,7 +132,7 @@ export class LucideAngularComponent implements OnChanges {
|
|||||||
...this.class
|
...this.class
|
||||||
.split(/ /)
|
.split(/ /)
|
||||||
.map((a) => a.trim())
|
.map((a) => a.trim())
|
||||||
.filter((a) => a.length > 0)
|
.filter((a) => a.length > 0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const childElements = this.elem.nativeElement.childNodes;
|
const childElements = this.elem.nativeElement.childNodes;
|
||||||
@@ -145,7 +145,7 @@ export class LucideAngularComponent implements OnChanges {
|
|||||||
toPascalCase(str: string): string {
|
toPascalCase(str: string): string {
|
||||||
return str.replace(
|
return str.replace(
|
||||||
/(\w)([a-z0-9]*)(_|-|\s*)/g,
|
/(\w)([a-z0-9]*)(_|-|\s*)/g,
|
||||||
(g0, g1, g2) => g1.toUpperCase() + g2.toLowerCase()
|
(g0, g1, g2) => g1.toUpperCase() + g2.toLowerCase(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ export class LucideAngularComponent implements OnChanges {
|
|||||||
private createElement([tag, attrs, children = []]: readonly [
|
private createElement([tag, attrs, children = []]: readonly [
|
||||||
string,
|
string,
|
||||||
SvgAttributes,
|
SvgAttributes,
|
||||||
LucideIconData?
|
LucideIconData?,
|
||||||
]) {
|
]) {
|
||||||
const element = this.renderer.createElement(tag, 'http://www.w3.org/2000/svg');
|
const element = this.renderer.createElement(tag, 'http://www.w3.org/2000/svg');
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,23 @@ import 'zone.js';
|
|||||||
import 'zone.js/testing';
|
import 'zone.js/testing';
|
||||||
import { getTestBed } from '@angular/core/testing';
|
import { getTestBed } from '@angular/core/testing';
|
||||||
import {
|
import {
|
||||||
BrowserDynamicTestingModule,
|
BrowserDynamicTestingModule,
|
||||||
platformBrowserDynamicTesting
|
platformBrowserDynamicTesting,
|
||||||
} from '@angular/platform-browser-dynamic/testing';
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
declare const require: {
|
declare const require: {
|
||||||
context(path: string, deep?: boolean, filter?: RegExp): {
|
context(
|
||||||
<T>(id: string): T;
|
path: string,
|
||||||
keys(): string[];
|
deep?: boolean,
|
||||||
};
|
filter?: RegExp,
|
||||||
|
): {
|
||||||
|
<T>(id: string): T;
|
||||||
|
keys(): string[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// First, initialize the Angular testing environment.
|
// First, initialize the Angular testing environment.
|
||||||
getTestBed().initTestEnvironment(
|
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||||
BrowserDynamicTestingModule,
|
|
||||||
platformBrowserDynamicTesting(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Then we find all the tests.
|
// Then we find all the tests.
|
||||||
const context = require.context('./', true, /\.spec\.ts$/);
|
const context = require.context('./', true, /\.spec\.ts$/);
|
||||||
|
|||||||
@@ -10,9 +10,7 @@
|
|||||||
"noPropertyAccessFromIndexSignature": true,
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"lucide-angular": [
|
"lucide-angular": ["dist"],
|
||||||
"dist"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
@@ -23,15 +21,12 @@
|
|||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"module": "es2020",
|
"module": "es2020",
|
||||||
"lib": [
|
"lib": ["es2020", "dom"],
|
||||||
"es2020",
|
|
||||||
"dom"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"enableI18nLegacyMessageIdFormat": false,
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
"strictInjectionParameters": true,
|
"strictInjectionParameters": true,
|
||||||
"strictInputAccessModifiers": true,
|
"strictInputAccessModifiers": true,
|
||||||
"strictTemplates": true
|
"strictTemplates": true,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,5 @@
|
|||||||
"inlineSources": true,
|
"inlineSources": true,
|
||||||
"types": []
|
"types": []
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
||||||
"src/test.ts",
|
|
||||||
"**/*.spec.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,8 @@
|
|||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./out-tsc/spec",
|
"outDir": "./out-tsc/spec",
|
||||||
"types": [
|
"types": ["jasmine"]
|
||||||
"jasmine"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": ["src/test.ts"],
|
||||||
"src/test.ts"
|
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||||
],
|
|
||||||
"include": [
|
|
||||||
"**/*.spec.ts",
|
|
||||||
"**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,95 @@
|
|||||||
import iconNodeToSvg from "../helpers/iconNodeToSvg"
|
import iconNodeToSvg from '../helpers/iconNodeToSvg';
|
||||||
|
|
||||||
export type IconNode = any[]
|
export type IconNode = any[];
|
||||||
export type IconName = string
|
export type IconName = string;
|
||||||
|
|
||||||
export type Tag = string[]
|
export type Tag = string[];
|
||||||
export interface Tags {
|
export interface Tags {
|
||||||
[key:string]: Tag
|
[key: string]: Tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LucideIcons {
|
export interface LucideIcons {
|
||||||
version: string
|
version: string;
|
||||||
iconNodes: { [key: IconName]: IconNode }
|
iconNodes: { [key: IconName]: IconNode };
|
||||||
tags: Tags,
|
tags: Tags;
|
||||||
svgs: { [key: IconName]: string }
|
svgs: { [key: IconName]: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchIcons = async (cachedIcons? : LucideIcons): Promise<LucideIcons> => {
|
export const fetchIcons = async (cachedIcons?: LucideIcons): Promise<LucideIcons> => {
|
||||||
const response = await fetch('https://unpkg.com/lucide-static@latest/package.json')
|
const response = await fetch('https://unpkg.com/lucide-static@latest/package.json');
|
||||||
const packageJson = await response.json();
|
const packageJson = await response.json();
|
||||||
|
|
||||||
if(cachedIcons && cachedIcons?.version === packageJson.version) {
|
if (cachedIcons && cachedIcons?.version === packageJson.version) {
|
||||||
return cachedIcons
|
return cachedIcons;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [iconNodesResponse, tagsResponse] = await Promise.all([
|
const [iconNodesResponse, tagsResponse] = await Promise.all([
|
||||||
fetch('https://lucide.dev/api/icon-nodes'),
|
fetch('https://lucide.dev/api/icon-nodes'),
|
||||||
fetch('https://lucide.dev/api/tags')
|
fetch('https://lucide.dev/api/tags'),
|
||||||
])
|
]);
|
||||||
|
|
||||||
const iconNodes = await iconNodesResponse.json();
|
const iconNodes = await iconNodesResponse.json();
|
||||||
const tags = await tagsResponse.json();
|
const tags = await tagsResponse.json();
|
||||||
const svgs = Object.keys(iconNodes).reduce((acc : { [key:string]: string}, iconName) => {
|
const svgs = Object.keys(iconNodes).reduce((acc: { [key: string]: string }, iconName) => {
|
||||||
acc[iconName] = iconNodeToSvg(iconName, iconNodes[iconName])
|
acc[iconName] = iconNodeToSvg(iconName, iconNodes[iconName]);
|
||||||
return acc
|
return acc;
|
||||||
}, {})
|
}, {});
|
||||||
|
|
||||||
const lucideIcons: LucideIcons = {
|
const lucideIcons: LucideIcons = {
|
||||||
version: packageJson.version,
|
version: packageJson.version,
|
||||||
tags,
|
tags,
|
||||||
iconNodes,
|
iconNodes,
|
||||||
svgs
|
svgs,
|
||||||
}
|
};
|
||||||
|
|
||||||
parent.postMessage({
|
parent.postMessage(
|
||||||
pluginMessage: {
|
{
|
||||||
type: "setCachedIcons",
|
pluginMessage: {
|
||||||
lucideIcons
|
type: 'setCachedIcons',
|
||||||
}
|
lucideIcons,
|
||||||
}, "*")
|
},
|
||||||
|
},
|
||||||
|
'*',
|
||||||
|
);
|
||||||
|
|
||||||
return lucideIcons
|
return lucideIcons;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getIcons = () => new Promise<LucideIcons>(async (resolve, reject)=> {
|
export const getIcons = () =>
|
||||||
|
new Promise<LucideIcons>(async (resolve, reject) => {
|
||||||
|
parent.postMessage(
|
||||||
|
{
|
||||||
|
pluginMessage: {
|
||||||
|
type: 'getCachedIcons',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'*',
|
||||||
|
);
|
||||||
|
|
||||||
parent.postMessage({
|
window.onmessage = async (event) => {
|
||||||
pluginMessage: {
|
if (event.type === 'message' && event?.data?.pluginMessage.type === 'cachedIcons') {
|
||||||
type: "getCachedIcons",
|
const lucideIcons = await fetchIcons(event?.data?.pluginMessage?.cachedIcons);
|
||||||
}
|
resolve(lucideIcons);
|
||||||
}, "*")
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
window.onmessage = async (event) => {
|
type EventCallback = (lucideIcons: LucideIcons) => void;
|
||||||
if (event.type === 'message' && event?.data?.pluginMessage.type === 'cachedIcons') {
|
|
||||||
|
|
||||||
const lucideIcons = await fetchIcons(event?.data?.pluginMessage?.cachedIcons)
|
|
||||||
resolve(lucideIcons)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
type EventCallback = (lucideIcons: LucideIcons) => void
|
|
||||||
|
|
||||||
export const iconFetchListener = (callback: EventCallback) => {
|
export const iconFetchListener = (callback: EventCallback) => {
|
||||||
fetchIcons()
|
fetchIcons();
|
||||||
|
|
||||||
const handleEvent = (event: MessageEvent) => {
|
const handleEvent = (event: MessageEvent) => {
|
||||||
if (event.type === 'message' && event?.data?.pluginMessage.type === 'cachedIcons') {
|
if (event.type === 'message' && event?.data?.pluginMessage.type === 'cachedIcons') {
|
||||||
|
const lucideIcons = event?.data?.pluginMessage?.cachedIcons;
|
||||||
const lucideIcons = event?.data?.pluginMessage?.cachedIcons
|
callback(lucideIcons);
|
||||||
callback(lucideIcons)
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
window.addEventListener('message', handleEvent)
|
window.addEventListener('message', handleEvent);
|
||||||
|
|
||||||
const removeListener = () => {
|
const removeListener = () => {
|
||||||
window.removeEventListener('message', handleEvent)
|
window.removeEventListener('message', handleEvent);
|
||||||
}
|
};
|
||||||
return removeListener
|
return removeListener;
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
const EditBar = () => {
|
const EditBar = () => {};
|
||||||
|
|
||||||
}
|
export default EditBar;
|
||||||
|
|
||||||
export default EditBar
|
|
||||||
|
|||||||
@@ -1,32 +1,37 @@
|
|||||||
import { renderToString } from 'react-dom/server'
|
import { renderToString } from 'react-dom/server';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import './IconButton.scss'
|
import './IconButton.scss';
|
||||||
|
|
||||||
interface IconButtonProps {
|
interface IconButtonProps {
|
||||||
name: string,
|
name: string;
|
||||||
component: FC,
|
component: FC;
|
||||||
}
|
}
|
||||||
|
|
||||||
function IconButton({ name, component: IconComponent }: IconButtonProps) {
|
function IconButton({ name, component: IconComponent }: IconButtonProps) {
|
||||||
const onIconClick = () => {
|
const onIconClick = () => {
|
||||||
const svg = renderToString(<IconComponent/>);
|
const svg = renderToString(<IconComponent />);
|
||||||
|
|
||||||
parent.postMessage({ pluginMessage: {
|
parent.postMessage(
|
||||||
type: 'drawIcon',
|
{
|
||||||
icon: { name, svg }
|
pluginMessage: {
|
||||||
}}, '*')
|
type: 'drawIcon',
|
||||||
}
|
icon: { name, svg },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'*',
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={name}
|
key={name}
|
||||||
aria-label={name}
|
aria-label={name}
|
||||||
onClick={onIconClick}
|
onClick={onIconClick}
|
||||||
className='icon-button'
|
className="icon-button"
|
||||||
>
|
>
|
||||||
<IconComponent />
|
<IconComponent />
|
||||||
</button>
|
</button>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default IconButton
|
export default IconButton;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './IconButton'
|
export { default } from './IconButton';
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react';
|
||||||
import './Menu.scss'
|
import './Menu.scss';
|
||||||
|
|
||||||
interface MenuProps {
|
interface MenuProps {
|
||||||
page: string
|
page: string;
|
||||||
setPage: (page:string) => void
|
setPage: (page: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const menuItems = ['icons', 'info']
|
const menuItems = ['icons', 'info'];
|
||||||
|
|
||||||
const Menu = ({page, setPage = (page) => {}}: MenuProps) => {
|
const Menu = ({ page, setPage = (page) => {} }: MenuProps) => {
|
||||||
return (
|
return (
|
||||||
<nav className="menu">
|
<nav className="menu">
|
||||||
{ menuItems.map((menuItem) => (
|
{menuItems.map((menuItem) => (
|
||||||
<div className={`menu-item ${page === menuItem ? 'active' : null }`} onClick={() => setPage(menuItem)}>
|
<div
|
||||||
|
className={`menu-item ${page === menuItem ? 'active' : null}`}
|
||||||
|
onClick={() => setPage(menuItem)}
|
||||||
|
>
|
||||||
{menuItem}
|
{menuItem}
|
||||||
</div>
|
</div>
|
||||||
)) }
|
))}
|
||||||
</nav>
|
</nav>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Menu
|
export default Menu;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './Menu'
|
export { default } from './Menu';
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import "./SearchInput.scss"
|
import './SearchInput.scss';
|
||||||
import { ChangeEvent } from "react"
|
import { ChangeEvent } from 'react';
|
||||||
import SearchIcon from "../icons/SearchIcon"
|
import SearchIcon from '../icons/SearchIcon';
|
||||||
|
|
||||||
interface SearchInputProps extends React.HTMLProps<HTMLDivElement> {
|
interface SearchInputProps extends React.HTMLProps<HTMLDivElement> {
|
||||||
value: string,
|
value: string;
|
||||||
iconCount: number,
|
iconCount: number;
|
||||||
onChange: (event: ChangeEvent<HTMLInputElement>) => void
|
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
||||||
placeholder: string
|
placeholder: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchInput({ value, onChange, placeholder, className, ...props }: SearchInputProps) {
|
function SearchInput({ value, onChange, placeholder, className, ...props }: SearchInputProps) {
|
||||||
@@ -15,7 +15,7 @@ function SearchInput({ value, onChange, placeholder, className, ...props }: Sear
|
|||||||
className="search-input"
|
className="search-input"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<SearchIcon className='icon'/>
|
<SearchIcon className="icon" />
|
||||||
<input
|
<input
|
||||||
autoFocus
|
autoFocus
|
||||||
type="search"
|
type="search"
|
||||||
@@ -25,7 +25,7 @@ function SearchInput({ value, onChange, placeholder, className, ...props }: Sear
|
|||||||
className="input__field"
|
className="input__field"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SearchInput
|
export default SearchInput;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export { default } from './SearchInput'
|
export { default } from './SearchInput';
|
||||||
|
|||||||
@@ -8,12 +8,8 @@
|
|||||||
--block: rgba(0, 0, 0, 0.06);
|
--block: rgba(0, 0, 0, 0.06);
|
||||||
--loader: hsl(0 0% 89%);
|
--loader: hsl(0 0% 89%);
|
||||||
|
|
||||||
background: linear-gradient(
|
background:
|
||||||
-75deg,
|
linear-gradient(-75deg, transparent 40%, var(--loader), transparent 60%) 0 0 / 200% 100%,
|
||||||
transparent 40%,
|
|
||||||
var(--loader),
|
|
||||||
transparent 60%
|
|
||||||
) 0 0 / 200% 100%,
|
|
||||||
var(--block);
|
var(--block);
|
||||||
|
|
||||||
border-radius: calc(var(--padding) * 0.5);
|
border-radius: calc(var(--padding) * 0.5);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import './Skeleton.scss'
|
import './Skeleton.scss';
|
||||||
|
|
||||||
const Skeleton = () => {
|
const Skeleton = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{Array.from({length: 48 }, () => (
|
{Array.from({ length: 48 }, () => (
|
||||||
<div className="skeleton"/>
|
<div className="skeleton" />
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Skeleton
|
export default Skeleton;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { createElement, forwardRef } from 'react'
|
import { createElement, forwardRef } from 'react';
|
||||||
|
|
||||||
|
|
||||||
const SearchIcon = (props: any) => (
|
const SearchIcon = (props: any) => (
|
||||||
<svg
|
<svg
|
||||||
@@ -17,6 +16,6 @@ const SearchIcon = (props: any) => (
|
|||||||
stroke="none"
|
stroke="none"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
)
|
);
|
||||||
|
|
||||||
export default SearchIcon
|
export default SearchIcon;
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ const defaultAttributes = {
|
|||||||
strokeLinejoin: 'round',
|
strokeLinejoin: 'round',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
|
export interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
|
||||||
size?: string | number
|
size?: string | number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,7 +25,8 @@ export interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
|
|||||||
* @param {string} string
|
* @param {string} string
|
||||||
* @returns {string} A kebabized string
|
* @returns {string} A kebabized string
|
||||||
*/
|
*/
|
||||||
export const toKebabCase = (string: string) => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
export const toKebabCase = (string: string) =>
|
||||||
|
string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
||||||
|
|
||||||
const createIconComponent = (iconName: string, iconNode: IconNode) => {
|
const createIconComponent = (iconName: string, iconNode: IconNode) => {
|
||||||
const Component = forwardRef<SVGSVGElement, LucideProps>(
|
const Component = forwardRef<SVGSVGElement, LucideProps>(
|
||||||
@@ -43,7 +43,12 @@ const createIconComponent = (iconName: string, iconNode: IconNode) => {
|
|||||||
className: `lucide lucide-${toKebabCase(iconName)}`,
|
className: `lucide lucide-${toKebabCase(iconName)}`,
|
||||||
...rest,
|
...rest,
|
||||||
},
|
},
|
||||||
[...iconNode.map(([tag, attrs]: [tag:string, attrs: SVGProps<SVGSVGElement>]) => createElement(tag, attrs)), ...([children] || [])],
|
[
|
||||||
|
...iconNode.map(([tag, attrs]: [tag: string, attrs: SVGProps<SVGSVGElement>]) =>
|
||||||
|
createElement(tag, attrs),
|
||||||
|
),
|
||||||
|
...([children] || []),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -52,4 +57,4 @@ const createIconComponent = (iconName: string, iconNode: IconNode) => {
|
|||||||
return Component;
|
return Component;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default createIconComponent
|
export default createIconComponent;
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import { Tags } from "../api/fetchIcons";
|
import { Tags } from '../api/fetchIcons';
|
||||||
import { Icon } from "../hooks/useSearch";
|
import { Icon } from '../hooks/useSearch';
|
||||||
|
|
||||||
export default (icons: Icon[], tags: Tags ,query:string) =>
|
export default (icons: Icon[], tags: Tags, query: string) =>
|
||||||
icons.filter(([name]: Icon) => {
|
icons.filter(([name]: Icon) => {
|
||||||
const iconTags = tags && tags[name] ? tags[name] : []
|
const iconTags = tags && tags[name] ? tags[name] : [];
|
||||||
|
|
||||||
return [name, ...iconTags].some(
|
return [name, ...iconTags].some((item: string) => item.toLowerCase().includes(query));
|
||||||
(item:string) => item
|
});
|
||||||
.toLowerCase()
|
|
||||||
.includes(query)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { createElement } from "react";
|
import { createElement } from 'react';
|
||||||
import { renderToString } from "react-dom/server";
|
import { renderToString } from 'react-dom/server';
|
||||||
import { IconNode } from "../api/fetchIcons";
|
import { IconNode } from '../api/fetchIcons';
|
||||||
import createIconComponent from "./createIconComponent";
|
import createIconComponent from './createIconComponent';
|
||||||
|
|
||||||
const iconNodeToSvg = (iconName: string, iconNode : IconNode) => {
|
const iconNodeToSvg = (iconName: string, iconNode: IconNode) => {
|
||||||
const IconComponent = createIconComponent(iconName, iconNode)
|
const IconComponent = createIconComponent(iconName, iconNode);
|
||||||
return renderToString(createElement(IconComponent));
|
return renderToString(createElement(IconComponent));
|
||||||
}
|
};
|
||||||
|
|
||||||
export default iconNodeToSvg
|
export default iconNodeToSvg;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts string to camelcase
|
* Converts string to camelcase
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import { IconName, IconNode, Tags } from "../api/fetchIcons";
|
import { IconName, IconNode, Tags } from '../api/fetchIcons';
|
||||||
import filterIcons from "../helpers/filterIcons";
|
import filterIcons from '../helpers/filterIcons';
|
||||||
|
|
||||||
export type Icon = [
|
export type Icon = [name: IconName, iconNode: IconNode];
|
||||||
name: IconName,
|
|
||||||
iconNode: IconNode
|
|
||||||
]
|
|
||||||
|
|
||||||
function useSearch(icons: Icon[], tags: Tags ,query: string) {
|
function useSearch(icons: Icon[], tags: Tags, query: string) {
|
||||||
if(!query) return icons;
|
if (!query) return icons;
|
||||||
|
|
||||||
const searchString = query.toLowerCase()
|
const searchString = query.toLowerCase();
|
||||||
|
|
||||||
return filterIcons(icons, tags, searchString);
|
return filterIcons(icons, tags, searchString);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
<script type="module" src="./interface.tsx"></script>
|
<script
|
||||||
|
type="module"
|
||||||
|
src="./interface.tsx"
|
||||||
|
></script>
|
||||||
|
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('https://rsms.me/inter/font-files/Inter-Regular.woff2?v=3.9')
|
src:
|
||||||
format('woff2'),
|
url('https://rsms.me/inter/font-files/Inter-Regular.woff2?v=3.9') format('woff2'),
|
||||||
url('https://rsms.me/inter/font-files/Inter-Regular.woff?v=3.9')
|
url('https://rsms.me/inter/font-files/Inter-Regular.woff?v=3.9') format('woff');
|
||||||
format('woff');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@@ -14,10 +13,9 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('https://rsms.me/inter/font-files/Inter-Medium.woff2?v=3.9')
|
src:
|
||||||
format('woff2'),
|
url('https://rsms.me/inter/font-files/Inter-Medium.woff2?v=3.9') format('woff2'),
|
||||||
url('https://rsms.me/inter/font-files/Inter-Medium.woff?v=3.9')
|
url('https://rsms.me/inter/font-files/Inter-Medium.woff?v=3.9') format('woff');
|
||||||
format('woff');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
|||||||
@@ -1,54 +1,57 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom';
|
||||||
import * as views from '../views'
|
import * as views from '../views';
|
||||||
|
|
||||||
type Views = typeof views
|
type Views = typeof views;
|
||||||
|
|
||||||
import useSearch, { Icon } from '../hooks/useSearch'
|
import useSearch, { Icon } from '../hooks/useSearch';
|
||||||
|
|
||||||
import { getIcons, iconFetchListener, LucideIcons } from '../api/fetchIcons'
|
import { getIcons, iconFetchListener, LucideIcons } from '../api/fetchIcons';
|
||||||
import './interface.scss'
|
import './interface.scss';
|
||||||
import Menu from '../components/Menu'
|
import Menu from '../components/Menu';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [page, setPage] = useState('icons')
|
const [page, setPage] = useState('icons');
|
||||||
const [query, setQuery] = useState('')
|
const [query, setQuery] = useState('');
|
||||||
const [icons, setIcons] = useState<Icon[]>([])
|
const [icons, setIcons] = useState<Icon[]>([]);
|
||||||
const [tags, setTags] = useState({})
|
const [tags, setTags] = useState({});
|
||||||
const [version, setVersion ] = useState('')
|
const [version, setVersion] = useState('');
|
||||||
|
|
||||||
const searchResults = useMemo(() => useSearch(icons, tags, query), [icons, query])
|
const searchResults = useMemo(() => useSearch(icons, tags, query), [icons, query]);
|
||||||
|
|
||||||
const handleFetchResponse = async (lucideIcons: LucideIcons) => {
|
const handleFetchResponse = async (lucideIcons: LucideIcons) => {
|
||||||
const icons = Object.entries(lucideIcons.iconNodes)
|
const icons = Object.entries(lucideIcons.iconNodes);
|
||||||
|
|
||||||
setIcons(icons)
|
setIcons(icons);
|
||||||
setTags(lucideIcons.tags)
|
setTags(lucideIcons.tags);
|
||||||
setVersion(lucideIcons.version)
|
setVersion(lucideIcons.version);
|
||||||
}
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const removeListener = iconFetchListener(handleFetchResponse)
|
const removeListener = iconFetchListener(handleFetchResponse);
|
||||||
|
|
||||||
return removeListener
|
return removeListener;
|
||||||
}, [])
|
}, []);
|
||||||
|
|
||||||
const View = views?.[page as keyof Views] ?? views.icons
|
const View = views?.[page as keyof Views] ?? views.icons;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Menu page={page} setPage={setPage}/>
|
<Menu
|
||||||
|
page={page}
|
||||||
|
setPage={setPage}
|
||||||
|
/>
|
||||||
<View
|
<View
|
||||||
{...{
|
{...{
|
||||||
query,
|
query,
|
||||||
setQuery,
|
setQuery,
|
||||||
searchResults,
|
searchResults,
|
||||||
icons,
|
icons,
|
||||||
version
|
version,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.getElementById('root'))
|
ReactDOM.render(<App />, document.getElementById('root'));
|
||||||
|
|||||||
@@ -1,26 +1,34 @@
|
|||||||
import type { LucideIcons } from "./api/fetchIcons";
|
import type { LucideIcons } from './api/fetchIcons';
|
||||||
import filterIcons from "./helpers/filterIcons";
|
import filterIcons from './helpers/filterIcons';
|
||||||
|
|
||||||
figma.showUI(__uiFiles__.worker, { visible: false })
|
figma.showUI(__uiFiles__.worker, { visible: false });
|
||||||
|
|
||||||
let cachedIcons: LucideIcons
|
let cachedIcons: LucideIcons;
|
||||||
|
|
||||||
type InsertableNodes = FrameNode | GroupNode
|
type InsertableNodes = FrameNode | GroupNode;
|
||||||
|
|
||||||
function isInsertableNode (node: SceneNode): node is InsertableNodes {
|
function isInsertableNode(node: SceneNode): node is InsertableNodes {
|
||||||
return ['FRAME', 'GROUP'].includes(node.type)
|
return ['FRAME', 'GROUP'].includes(node.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
const setResults = ({result, query, lucideIcons} : { result: SuggestionResults, query: string, lucideIcons: LucideIcons }) => {
|
const setResults = ({
|
||||||
|
result,
|
||||||
|
query,
|
||||||
|
lucideIcons,
|
||||||
|
}: {
|
||||||
|
result: SuggestionResults;
|
||||||
|
query: string;
|
||||||
|
lucideIcons: LucideIcons;
|
||||||
|
}) => {
|
||||||
const icons = Object.entries(lucideIcons.iconNodes);
|
const icons = Object.entries(lucideIcons.iconNodes);
|
||||||
|
|
||||||
const suggestions = filterIcons(icons, lucideIcons.tags, query.toLowerCase()).map(([name]) => ({
|
const suggestions = filterIcons(icons, lucideIcons.tags, query.toLowerCase()).map(([name]) => ({
|
||||||
name,
|
name,
|
||||||
icon: lucideIcons.svgs[name]
|
icon: lucideIcons.svgs[name],
|
||||||
}))
|
}));
|
||||||
|
|
||||||
result.setSuggestions(suggestions)
|
result.setSuggestions(suggestions);
|
||||||
}
|
};
|
||||||
|
|
||||||
// const styles = figma.getLocalPaintStyles();
|
// const styles = figma.getLocalPaintStyles();
|
||||||
// const styleNames = styles.map((style) => style.name);
|
// const styleNames = styles.map((style) => style.name);
|
||||||
@@ -28,112 +36,114 @@ const setResults = ({result, query, lucideIcons} : { result: SuggestionResults,
|
|||||||
|
|
||||||
figma.parameters.on('input', async ({ parameters, key, query, result }) => {
|
figma.parameters.on('input', async ({ parameters, key, query, result }) => {
|
||||||
if (key === 'icon-name') {
|
if (key === 'icon-name') {
|
||||||
cachedIcons = await figma.clientStorage.getAsync(`lucide-icons`)
|
cachedIcons = await figma.clientStorage.getAsync(`lucide-icons`);
|
||||||
|
|
||||||
if(cachedIcons && cachedIcons.iconNodes && cachedIcons.tags) {
|
if (cachedIcons && cachedIcons.iconNodes && cachedIcons.tags) {
|
||||||
setResults({result, query, lucideIcons: cachedIcons})
|
setResults({ result, query, lucideIcons: cachedIcons });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(key === 'size') {
|
if (key === 'size') {
|
||||||
const iconSizes = [24,36,48,72]
|
const iconSizes = [24, 36, 48, 72];
|
||||||
result.setSuggestions(iconSizes.map((size)=>({
|
result.setSuggestions(
|
||||||
name: size.toString(),
|
iconSizes.map((size) => ({
|
||||||
data: size
|
name: size.toString(),
|
||||||
})))
|
data: size,
|
||||||
|
})),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const drawIcon = ({icon: {name, svg, size }}: any) => {
|
const drawIcon = ({ icon: { name, svg, size } }: any) => {
|
||||||
const min = 0
|
const min = 0;
|
||||||
const max = 100
|
const max = 100;
|
||||||
const randomPosition = () => Math.floor(Math.random() * (max - min + 1) + min)
|
const randomPosition = () => Math.floor(Math.random() * (max - min + 1) + min);
|
||||||
|
|
||||||
const icon = figma.createNodeFromSvg(svg)
|
const icon = figma.createNodeFromSvg(svg);
|
||||||
icon.setPluginData('isLucideIcon', 'true')
|
icon.setPluginData('isLucideIcon', 'true');
|
||||||
icon.setPluginData('iconName', name)
|
icon.setPluginData('iconName', name);
|
||||||
|
|
||||||
const pluginData = icon.getPluginData('isLucideIcon')
|
const pluginData = icon.getPluginData('isLucideIcon');
|
||||||
|
|
||||||
icon.name = name
|
icon.name = name;
|
||||||
icon.x = Math.round(figma.viewport.center.x + randomPosition())
|
icon.x = Math.round(figma.viewport.center.x + randomPosition());
|
||||||
icon.y = Math.round(figma.viewport.center.y + randomPosition())
|
icon.y = Math.round(figma.viewport.center.y + randomPosition());
|
||||||
|
|
||||||
if(figma.currentPage.selection.length) {
|
if (figma.currentPage.selection.length) {
|
||||||
let currentSelection = figma.currentPage.selection[0]
|
let currentSelection = figma.currentPage.selection[0];
|
||||||
const isLucideIcon = currentSelection.getPluginData('isLucideIcon')
|
const isLucideIcon = currentSelection.getPluginData('isLucideIcon');
|
||||||
|
|
||||||
// if(isLucideIcon && currentSelection?.parent) {
|
// if(isLucideIcon && currentSelection?.parent) {
|
||||||
// return
|
// return
|
||||||
// // currentSelection = currentSelection.parent as SceneNode
|
// // currentSelection = currentSelection.parent as SceneNode
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if(!isLucideIcon && isInsertableNode(currentSelection)) {
|
if (!isLucideIcon && isInsertableNode(currentSelection)) {
|
||||||
icon.x = currentSelection.type === 'GROUP' ? currentSelection.x : 0
|
icon.x = currentSelection.type === 'GROUP' ? currentSelection.x : 0;
|
||||||
icon.y = currentSelection.type === 'GROUP' ? currentSelection.y : 0
|
icon.y = currentSelection.type === 'GROUP' ? currentSelection.y : 0;
|
||||||
|
|
||||||
currentSelection.appendChild(icon)
|
currentSelection.appendChild(icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
figma.currentPage.selection = [icon]
|
figma.currentPage.selection = [icon];
|
||||||
|
|
||||||
// lock children
|
// lock children
|
||||||
// icon.children.forEach((vectorNode, key) => {
|
// icon.children.forEach((vectorNode, key) => {
|
||||||
// icon.children[key].locked = true
|
// icon.children[key].locked = true
|
||||||
// });
|
// });
|
||||||
}
|
};
|
||||||
|
|
||||||
const setCachedIcons = async (pluginMessage: any) => {
|
const setCachedIcons = async (pluginMessage: any) => {
|
||||||
if(pluginMessage.lucideIcons) {
|
if (pluginMessage.lucideIcons) {
|
||||||
await figma.clientStorage.setAsync(`lucide-icons`, pluginMessage.lucideIcons)
|
await figma.clientStorage.setAsync(`lucide-icons`, pluginMessage.lucideIcons);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const getCachedIcons = async () => {
|
const getCachedIcons = async () => {
|
||||||
cachedIcons = await figma.clientStorage.getAsync(`lucide-icons`)
|
cachedIcons = await figma.clientStorage.getAsync(`lucide-icons`);
|
||||||
|
|
||||||
const response = { type: 'cachedIcons' }
|
const response = { type: 'cachedIcons' };
|
||||||
|
|
||||||
if(cachedIcons) {
|
if (cachedIcons) {
|
||||||
Object.assign(response, { cachedIcons })
|
Object.assign(response, { cachedIcons });
|
||||||
}
|
}
|
||||||
|
|
||||||
figma.ui.postMessage(response)
|
figma.ui.postMessage(response);
|
||||||
}
|
};
|
||||||
|
|
||||||
getCachedIcons()
|
getCachedIcons();
|
||||||
|
|
||||||
figma.ui.onmessage = (event) => {
|
figma.ui.onmessage = (event) => {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case "drawIcon":
|
case 'drawIcon':
|
||||||
drawIcon(event)
|
drawIcon(event);
|
||||||
break;
|
break;
|
||||||
case "getCachedIcons":
|
case 'getCachedIcons':
|
||||||
getCachedIcons()
|
getCachedIcons();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "setCachedIcons":
|
case 'setCachedIcons':
|
||||||
setCachedIcons(event)
|
setCachedIcons(event);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "close":
|
case 'close':
|
||||||
figma.closePlugin()
|
figma.closePlugin();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
figma.on('run', event => {
|
figma.on('run', (event) => {
|
||||||
if(event.parameters) {
|
if (event.parameters) {
|
||||||
figma.ui.postMessage({
|
figma.ui.postMessage({
|
||||||
type: 'getSvg',
|
type: 'getSvg',
|
||||||
iconName: event.parameters['icon-name'],
|
iconName: event.parameters['icon-name'],
|
||||||
size: event.parameters['size'],
|
size: event.parameters['size'],
|
||||||
cachedIcons
|
cachedIcons,
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
figma.showUI(__uiFiles__.interface, { width: 300, height: 400 })
|
figma.showUI(__uiFiles__.interface, { width: 300, height: 400 });
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ export default {
|
|||||||
blue: '#18a0fb',
|
blue: '#18a0fb',
|
||||||
},
|
},
|
||||||
radii: [0, 2],
|
radii: [0, 2],
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,59 +1,52 @@
|
|||||||
import IconButton from '../components/IconButton'
|
import IconButton from '../components/IconButton';
|
||||||
import SearchInput from '../components/SearchInput'
|
import SearchInput from '../components/SearchInput';
|
||||||
import createIconComponent from '../helpers/createIconComponent'
|
import createIconComponent from '../helpers/createIconComponent';
|
||||||
import { Icon } from '../hooks/useSearch'
|
import { Icon } from '../hooks/useSearch';
|
||||||
import Skeleton from '../components/Skeleton/Skeleton'
|
import Skeleton from '../components/Skeleton/Skeleton';
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
query: string
|
query: string;
|
||||||
setQuery: (query:string) => void
|
setQuery: (query: string) => void;
|
||||||
searchResults: Icon[]
|
searchResults: Icon[];
|
||||||
icons: Icon[]
|
icons: Icon[];
|
||||||
version: string
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Icons = ({
|
const Icons = ({ query, setQuery, searchResults, icons, version }: PageProps) => {
|
||||||
query,
|
|
||||||
setQuery,
|
|
||||||
searchResults,
|
|
||||||
icons,
|
|
||||||
version
|
|
||||||
}: PageProps) => {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
value={query}
|
value={query}
|
||||||
iconCount={icons.length}
|
iconCount={icons.length}
|
||||||
onChange={(event) => setQuery(event.target.value)}
|
onChange={(event) => setQuery(event.target.value)}
|
||||||
placeholder={icons.length ? `Search ${icons.length} icons`: 'Loading icons ..'}
|
placeholder={icons.length ? `Search ${icons.length} icons` : 'Loading icons ..'}
|
||||||
/>
|
/>
|
||||||
<main>
|
<main>
|
||||||
<div className='icon-grid'>
|
<div className="icon-grid">
|
||||||
{icons.length ? (
|
{icons.length ? (
|
||||||
searchResults.map(([name, iconNode]: any) => (
|
searchResults.map(([name, iconNode]: any) => (
|
||||||
<IconButton
|
<IconButton
|
||||||
name={name}
|
name={name}
|
||||||
key={name}
|
key={name}
|
||||||
component={createIconComponent(name, iconNode)}
|
component={createIconComponent(name, iconNode)}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<Skeleton />
|
<Skeleton />
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
<footer>
|
||||||
<footer>
|
<a
|
||||||
<a
|
href="https://lucide.dev"
|
||||||
href="https://lucide.dev"
|
target="_blank"
|
||||||
target="_blank"
|
className="footer-link"
|
||||||
className='footer-link'
|
>
|
||||||
>
|
Lucide v{version}
|
||||||
Lucide v{version}
|
</a>
|
||||||
</a>
|
</footer>
|
||||||
</footer>
|
</main>
|
||||||
</main>
|
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Icons
|
export default Icons;
|
||||||
|
|||||||
@@ -1,64 +1,70 @@
|
|||||||
import { SyntheticEvent } from "react"
|
import { SyntheticEvent } from 'react';
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
version: string
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Info = ({ version }: PageProps) => {
|
const Info = ({ version }: PageProps) => {
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{
|
{
|
||||||
name: 'Report a bug',
|
name: 'Report a bug',
|
||||||
url: 'https://github.com/lucide-icons/lucide/issues'
|
url: 'https://github.com/lucide-icons/lucide/issues',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Contribute an icon',
|
name: 'Contribute an icon',
|
||||||
url: 'https://github.com/lucide-icons/lucide/blob/main/CONTRIBUTING.md'
|
url: 'https://github.com/lucide-icons/lucide/blob/main/CONTRIBUTING.md',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Website',
|
name: 'Website',
|
||||||
url: 'https://lucide.dev'
|
url: 'https://lucide.dev',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Repository',
|
name: 'Repository',
|
||||||
url: 'https://github.com/lucide-icons/lucide'
|
url: 'https://github.com/lucide-icons/lucide',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'License',
|
name: 'License',
|
||||||
url: 'https://lucide.dev/license'
|
url: 'https://lucide.dev/license',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Community Page',
|
name: 'Community Page',
|
||||||
url: 'https://www.figma.com/community/plugin/939567362549682242/Lucide-Icons'
|
url: 'https://www.figma.com/community/plugin/939567362549682242/Lucide-Icons',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Supported Frameworks',
|
name: 'Supported Frameworks',
|
||||||
url: 'https://lucide.dev/packages'
|
url: 'https://lucide.dev/packages',
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const onClick = (url: string) => (event: SyntheticEvent) => {
|
const onClick = (url: string) => (event: SyntheticEvent) => {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
|
|
||||||
window.open(url,'_blank')
|
window.open(url, '_blank');
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="info-page">
|
<div className="info-page">
|
||||||
<img src="https://lucide.dev/logo-text.svg" alt="Lucide Logo" className="lucide-logo"/>
|
<img
|
||||||
<p className='version'>
|
src="https://lucide.dev/logo-text.svg"
|
||||||
v{version}
|
alt="Lucide Logo"
|
||||||
</p>
|
className="lucide-logo"
|
||||||
|
/>
|
||||||
|
<p className="version">v{version}</p>
|
||||||
<section className="link-list">
|
<section className="link-list">
|
||||||
{
|
{menuItems.map(({ name, url }) => (
|
||||||
menuItems.map(({ name, url }) => (
|
<a
|
||||||
<a href={url} key={name} aria-label={name} className="info-link" onClick={onClick(url)}>
|
href={url}
|
||||||
{name}
|
key={name}
|
||||||
</a>
|
aria-label={name}
|
||||||
))
|
className="info-link"
|
||||||
}
|
onClick={onClick(url)}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Info
|
export default Info;
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export { default as icons } from './Icons'
|
export { default as icons } from './Icons';
|
||||||
export { default as info } from './Info'
|
export { default as info } from './Info';
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user