Compare commits

..

5 Commits

Author SHA1 Message Date
Eric Fennis
d1d57d3c85 Format code 2025-07-04 17:40:28 +02:00
Eric Fennis
701c2fb6b2 Delete lucide-vue 2024-01-23 18:24:03 +01:00
Eric Fennis
294ec9c727 Add simlinks 2024-01-23 17:46:05 +01:00
Eric Fennis
99c883e60a revert import change 2024-01-23 17:45:55 +01:00
Eric Fennis
9e68779d22 create new vue directory 2024-01-23 17:45:43 +01:00
1884 changed files with 7884 additions and 19116 deletions

View File

@@ -1,16 +0,0 @@
# Custom words
fullscreen
gamepad
gantt
kanban
pilcrow
squircle
strikethrough
touchpad
ungroup
pilcrow
# Brands
codepen
codesandbox
dribbble

View File

@@ -6,5 +6,6 @@ tests
node_modules
.eslintrc.js
docs/images
docs/**/examples/
docs/guide/basics/examples
docs/guide/advanced/examples
packages/lucide-react/dynamicIconImports.js

View File

@@ -42,15 +42,12 @@ module.exports = {
'@html-eslint/no-duplicate-attrs': 'error',
'@html-eslint/no-inline-styles': 'error',
'@html-eslint/require-attrs': [
'error',
...Object.entries(DEFAULT_ATTRS).map(([attr, value]) => ({
tag: 'svg',
attr,
value: String(value),
})),
'error',
...Object.entries(DEFAULT_ATTRS)
.map(([attr, value]) => ({ tag: 'svg', attr, value: String(value) }))
],
'@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': [
'error',
{
@@ -67,7 +64,7 @@ module.exports = {
'@html-eslint/element-newline': 'error',
'@html-eslint/no-trailing-spaces': 'error',
'@html-eslint/quotes': 'error',
},
}
},
],
};

View File

@@ -35,16 +35,6 @@ body:
placeholder: e.g. 0.289.1
validations:
required: true
- type: checkboxes
id: can-reproduce-in-latest-version
attributes:
label: Can you reproduce this in the latest version?
description: i.e. after running `npm install lucide-react@latest`
options:
- label: 'Yes'
- label: 'No'
validations:
required: false
- type: checkboxes
id: browsers
attributes:

View File

@@ -1,5 +1,5 @@
name: 'Build and Test'
description: 'Builds and test a package'
name: "Build and Test"
description: "Builds and test a package"
inputs:
name:
@@ -7,7 +7,7 @@ inputs:
required: true
runs:
using: 'composite'
using: "composite"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4

View File

@@ -1,5 +1,5 @@
name: 'Check icons'
description: 'Cross-checks icon and category references in JSON descriptors'
name: "Check icons"
description: "Cross-checks icon and category references in JSON descriptors"
inputs:
name:
@@ -7,7 +7,7 @@ inputs:
required: true
runs:
using: 'composite'
using: "composite"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4

96
.github/labeler.yml vendored
View File

@@ -1,92 +1,92 @@
# For changed dependencies
📦 dependencies:
- changed-files:
- any-glob-to-any-file:
- pnpm-lock.yaml
- changed-files:
- any-glob-to-any-file:
- pnpm-lock.yaml
# For changes in documentation
📖 documentation:
- changed-files:
- any-glob-to-any-file:
- docs/*.md
- docs/**/*.md
- changed-files:
- any-glob-to-any-file:
- docs/*.md
- docs/**/*.md
# For changes in the site, but not markdown files
🌍 site:
- changed-files:
- any-glob-to-any-file:
- 'docs/**'
- changed-files:
- any-glob-to-any-file:
- 'docs/**'
# For changes in the metadata
🫧 metadata:
- changed-files:
- any-glob-to-any-file:
- 'icons/*.json'
- categories/*
- changed-files:
- any-glob-to-any-file:
- 'icons/*.json'
- categories/*
# For changes or added icons
🎨 icon:
- changed-files:
- any-glob-to-any-file:
- 'icons/*.svg'
- changed-files:
- any-glob-to-any-file:
- 'icons/*.svg'
# For changes in the lucide package
🧳 lucide package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide/*'
# For changes in the lucide React package
⚛️ react package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react/*'
# For changes in the lucide React Native package
⚛️ react native package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react-native/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-react-native/*'
# For changes in the lucide vue packages
💎 vue package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-vue/*'
- 'packages/lucide-vue-next/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-vue/*'
- 'packages/lucide-vue-next/*'
# For changes in the lucide angular package
🅰️ angular package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-angular/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-angular/*'
# For changes in the lucide preact package
⚛️ preact package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-preact/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-preact/*'
# For changes in the lucide svelte package
🧣 svelte package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-svelte/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-svelte/*'
# For changes in the lucide solid package
🪝 solid package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-solid/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-solid/*'
# For changes in the lucide static package
🪨 static package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-static/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-static/*'
# For changes in the lucide flutter package
🏹 flutter package:
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-flutter/*'
- changed-files:
- any-glob-to-any-file:
- 'packages/lucide-flutter/*'

View File

@@ -47,7 +47,7 @@
- [ ] I've made sure that the icons look sharp on low DPI displays.
- [ ] I've made sure that the icons look consistent with the icon set in size, optical volume and density.
- [ ] I've made sure that the icons are visually centered.
- [ ] I've correctly optimized all icons to three points of precision.
- [ ] I've correctly optimized all icons to two points of precision.
## Before Submitting <!-- For every PR! -->
<!-- All of these requirements must be fulfilled. -->

View File

@@ -1,13 +1,11 @@
name: Close stale issues and PR
on:
schedule:
- cron: '45 1 * * *'
- cron: "45 1 * * *"
jobs:
stale:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/stale@v9
with:
@@ -16,5 +14,4 @@ jobs:
close-pr-message: This PR was closed because it has been stalled for 5 days with no activity.
close-pr-label: 🧶 stale
days-before-stale: 30
days-before-issue-stale: -1
days-before-close: -1

View File

@@ -1,6 +1,6 @@
name: 'Pull Request Labeler'
name: "Pull Request Labeler"
on:
- pull_request_target
- pull_request_target
jobs:
triage:
@@ -9,4 +9,4 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@v5

View File

@@ -29,7 +29,7 @@ jobs:
- name: Create font in ./lucide-font
run: pnpm build:font
- name: 'Upload to Artifacts'
- name: "Upload to Artifacts"
uses: actions/upload-artifact@v3
with:
name: lucide-font

View File

@@ -94,10 +94,6 @@ jobs:
comment-author: 'github-actions[bot]'
body-includes: Added or changed icons
- uses: actions/setup-node@v4
- name: Install svgson for code preview (safer and faster than installing all deps)
run: npm install svgson
- name: Generate comment markup
run: node ./scripts/generateChangedIconsCommentMarkup.mjs >> comment-markup.md
id: comment-markup

View File

@@ -41,18 +41,17 @@ jobs:
strategy:
fail-fast: false
matrix:
package:
[
'lucide',
'lucide-react',
'lucide-react-native',
'lucide-vue',
'lucide-vue-next',
'lucide-angular',
'lucide-preact',
'lucide-solid',
'lucide-svelte',
]
package: [
'lucide',
'lucide-react',
'lucide-react-native',
'lucide-vue',
'lucide-vue-next',
'lucide-angular',
'lucide-preact',
'lucide-solid',
'lucide-svelte',
]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
@@ -137,7 +136,7 @@ jobs:
- name: Create font in ./lucide-font
run: pnpm build:font
- name: 'Upload to Artifacts'
- name: "Upload to Artifacts"
uses: actions/upload-artifact@v3
with:
name: lucide-font
@@ -146,7 +145,10 @@ jobs:
post-release:
if: github.repository == 'lucide-icons/lucide'
runs-on: ubuntu-latest
needs: [pre-release, lucide-font]
needs: [
pre-release,
lucide-font,
]
steps:
- uses: actions/checkout@v4

View File

@@ -1,8 +1,5 @@
pnpm-lock.yaml
# docs examples
docs/**/examples/
# lucide-angular
packages/lucide-angular/.angular/cache

2
.vscode/launch.json vendored
View File

@@ -12,4 +12,4 @@
"webRoot": "${workspaceFolder}"
}
]
}
}

11
.vscode/settings.json vendored
View File

@@ -1,6 +1,13 @@
{
"cSpell.words": ["devs", "preact", "Preact"],
"cSpell.words": [
"devs",
"preact",
"Preact"
],
"eslint.enable": true,
"eslint.validate": ["javascript", "svg"],
"eslint.validate": [
"javascript",
"svg"
],
"svg.preview.background": "transparent"
}

View File

@@ -49,7 +49,7 @@
"circle",
"<circle"
],
"body": "<circle cx=\"${2:12}\" cy=\"${3:$2}\" r=\"${1|10,2,.5\" fill=\"currentColor|}\" />"
"body": "<circle cx=\"${2:12}\" cy=\"${3:$2}\" r=\"${1|10,2,.5|}\" />"
},
"Ellipse": {
"scope": "xml",

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Accessibility",
"icon": "accessibility"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Accounts & access",
"icon": "user"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Animals",
"icon": "dog"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Arrows",
"icon": "arrow-left-right"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Brands",
"icon": "facebook"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Buildings",
"icon": "building"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Charts",
"icon": "pie-chart"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Communication",
"icon": "message-circle"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Connectivity",
"icon": "wifi"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Currency",
"icon": "dollar-sign"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Cursors",
"icon": "mouse-pointer-2"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Design",
"icon": "palette"
}
}

View File

@@ -1,5 +1,5 @@
{
"$schema": "../category.schema.json",
"title": "Coding & development",
"icon": "code-xml"
"icon": "code-2"
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Devices",
"icon": "smartphone"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Emoji",
"icon": "smile"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "File icons",
"icon": "panels-top-left"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Food & beverage",
"icon": "coffee"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Furniture",
"icon": "rocking-chair"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Gaming",
"icon": "gamepad-2"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Home",
"icon": "home"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Layout",
"icon": "panels-top-left"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Mail",
"icon": "mail"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Maps",
"icon": "map"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Maths",
"icon": "divide"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Medical",
"icon": "heart"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Money",
"icon": "piggy-bank"
}
}

View File

@@ -1,5 +1,5 @@
{
"$schema": "../category.schema.json",
"title": "Multimedia",
"icon": "circle-play"
}
"icon": "play-circle"
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Nature",
"icon": "sprout"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Navigation",
"icon": "compass"
}
}

View File

@@ -1,5 +1,5 @@
{
"$schema": "../category.schema.json",
"title": "Notifications",
"icon": "triangle-alert"
}
"icon": "alert-triangle"
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "People",
"icon": "person-standing"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Photography",
"icon": "camera"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Science",
"icon": "flask-conical"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Seasons",
"icon": "leaf"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Security",
"icon": "shield"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Shapes",
"icon": "triangle"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Shopping",
"icon": "shopping-bag"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Social",
"icon": "thumbs-up"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Sports",
"icon": "type"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Sustainability",
"icon": "recycle"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Time & calendar",
"icon": "calendar"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Tools",
"icon": "hammer"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Transportation",
"icon": "train-front"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Travel",
"icon": "backpack"
}
}

View File

@@ -2,4 +2,4 @@
"$schema": "../category.schema.json",
"title": "Weather",
"icon": "cloud-sun"
}
}

View File

@@ -1,10 +0,0 @@
{
"dictionaries": ["en-us", "custom-words"],
"dictionaryDefinitions": [
{
"name": "custom-words",
"path": "./.cspell/custom-words.txt",
"addWords": true
}
]
}

View File

@@ -1,11 +1,11 @@
import { eventHandler, setResponseHeader } from 'h3';
import iconMetaData from '../../data/iconMetaData';
import { eventHandler, setResponseHeader } from 'h3'
import iconMetaData from '../../data/iconMetaData'
export default eventHandler((event) => {
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
return Object.fromEntries(
Object.entries(iconMetaData).map(([name, { categories }]) => [name, categories]),
);
});
Object.entries(iconMetaData).map(([name, { categories }]) => [ name, categories ])
)
})

View File

@@ -37,13 +37,13 @@ export default eventHandler((event) => {
backdropString,
src,
color: name in iconNodes ? 'red' : '#777',
}),
})
);
}
const svg = Buffer.from(
// 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');
defaultContentType(event, 'image/svg+xml');

View File

@@ -28,7 +28,7 @@ export default eventHandler(async (event) => {
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
`,
`
);
const resvg = new Resvg(svg, { background: '#000' });

View File

@@ -1,12 +1,12 @@
import { eventHandler, setResponseHeader, defaultContentType } from 'h3';
import { renderToString } from 'react-dom/server';
import { createElement } from 'react';
import { eventHandler, setResponseHeader, defaultContentType } from 'h3'
import { renderToString } from 'react-dom/server'
import { createElement } from 'react'
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';
export default eventHandler((event) => {
const { params } = event.context;
const { params } = event.context
const [strokeWidth, svgData] = params.data.split('/');
const data = svgData.slice(0, -4);
@@ -16,8 +16,8 @@ export default eventHandler((event) => {
const Icon = createLucideIcon(
'icon',
parseSync(src.includes('<svg') ? src : `<svg>${src}</svg>`).children.map(
({ name, attributes }) => [name, attributes],
) as IconNode,
({ name, attributes }) => [name, attributes]
) as IconNode
);
const svg = Buffer.from(
@@ -33,12 +33,12 @@ export default eventHandler((event) => {
@media screen and (prefers-color-scheme: dark) {
svg { stroke: #fff; fill: transparent !important; }
}
</style>`,
),
</style>`
)
).toString('utf8');
defaultContentType(event, 'image/svg+xml');
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
defaultContentType(event, 'image/svg+xml')
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
return svg;
});
return svg
})

View File

@@ -1,30 +1,30 @@
import { eventHandler, getQuery, setResponseHeader } from 'h3';
import iconNodes from '../../data/iconNodes';
import { IconNodeWithKeys } from '../../theme/types';
import { eventHandler, getQuery, setResponseHeader } from 'h3'
import iconNodes from '../../data/iconNodes'
import { IconNodeWithKeys } from '../../theme/types'
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, 'Access-Control-Allow-Origin', '*');
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
if (withUniqueKeys) {
return iconNodes;
return iconNodes
}
return Object.entries(iconNodes).reduce((acc, [name, iconNode]) => {
if (withUniqueKeys) {
return [name, iconNode];
return [name, iconNode]
}
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs }]) => {
return [name, attrs];
});
const newIconNode = (iconNode as IconNodeWithKeys).map(([name, { key, ...attrs}]) => {
return [name, attrs]
})
acc[name] = newIconNode;
acc[name] = newIconNode
return acc;
}, {});
});
return acc
}, {})
})

View File

@@ -1,29 +1,29 @@
import { eventHandler, getQuery, setResponseHeader, createError } from 'h3';
import iconNodes from '../../data/iconNodes';
import createLucideIcon from 'lucide-react/src/createLucideIcon';
import { renderToString } from 'react-dom/server';
import { createElement } from 'react';
import { eventHandler, getQuery, setResponseHeader, createError } from 'h3'
import iconNodes from '../../data/iconNodes'
import createLucideIcon from 'lucide-react/src/createLucideIcon'
import { renderToString } from 'react-dom/server'
import { createElement } from 'react'
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) {
const error = createError({
statusCode: 404,
message: `Icon "${params.iconName}" not found`,
});
})
return sendError(event, error);
return sendError(event, error)
}
const width = getQuery(event).width || undefined;
const height = getQuery(event).height || undefined;
const color = getQuery(event).color || undefined;
const strokeWidth = getQuery(event).strokeWidth || undefined;
const width = getQuery(event).width || undefined
const height = getQuery(event).height || undefined
const color = getQuery(event).color || undefined
const strokeWidth = getQuery(event).strokeWidth || undefined
const LucideIcon = createLucideIcon(params.iconName, iconNode);
const LucideIcon = createLucideIcon(params.iconName, iconNode)
const svg = Buffer.from(
renderToString(
@@ -32,13 +32,14 @@ export default eventHandler((event) => {
height,
color: color ? `#${color}` : undefined,
strokeWidth,
}),
),
}
))
).toString('utf8');
defaultContentType(event, 'image/svg+xml');
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
defaultContentType(event, 'image/svg+xml')
setResponseHeader(event, 'Cache-Control', 'public,max-age=31536000')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
return svg;
});
return svg
})

View File

@@ -1,9 +1,11 @@
import { eventHandler, setResponseHeader } from 'h3';
import iconMetaData from '../../data/iconMetaData';
import { eventHandler, setResponseHeader } from 'h3'
import iconMetaData from '../../data/iconMetaData'
export default eventHandler((event) => {
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400');
setResponseHeader(event, 'Access-Control-Allow-Origin', '*');
setResponseHeader(event, 'Cache-Control', 'public, max-age=86400')
setResponseHeader(event, 'Access-Control-Allow-Origin', '*')
return Object.fromEntries(Object.entries(iconMetaData).map(([name, { tags }]) => [name, tags]));
});
return Object.fromEntries(
Object.entries(iconMetaData).map(([name, { tags }]) => [ name, tags ])
)
})

View File

@@ -1,3 +1,3 @@
export default eventHandler(() => {
return { nitro: 'Is Awesome! asda' };
});
return { nitro: 'Is Awesome! asda' }
})

View File

@@ -1,10 +1,10 @@
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vitepress';
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vitepress'
import sidebar from './sidebar';
const title = 'Lucide';
const socialTitle = 'Lucide Icons';
const description = 'Beautiful & consistent icon toolkit made by the community.';
const title = "Lucide";
const socialTitle = "Lucide Icons";
const description = "Beautiful & consistent icon toolkit made by the community."
// https://vitepress.dev/reference/site-config
export default defineConfig({
@@ -19,131 +19,86 @@ export default defineConfig({
{
find: /^.*\/VPIconAlignLeft\.vue$/,
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$/,
replacement: fileURLToPath(
new URL('./theme/components/overrides/VPFooter.vue', import.meta.url),
),
},
],
new URL('./theme/components/overrides/VPFooter.vue', import.meta.url)
)
}
]
},
},
head: [
[
'script',
{
src: 'https://analytics.lucide.dev/js/script.js',
'data-domain': 'lucide.dev',
defer: '',
},
],
[
'meta',
{
property: 'og:locale',
content: 'en_US',
},
],
[
'meta',
{
property: 'og:type',
content: 'website',
},
],
[
'meta',
{
property: 'og:site_name',
content: title,
},
],
[
'meta',
{
property: 'og:title',
content: socialTitle,
},
],
[
'meta',
{
property: 'og:description',
content: description,
},
],
[
'meta',
{
property: 'og:url',
content: 'https://lucide.dev',
},
],
[
'meta',
{
property: 'og:image',
content: 'https://lucide.dev/og.png',
},
],
[
'meta',
{
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',
},
],
[ 'script', {
src: 'https://analytics.lucide.dev/js/script.js',
'data-domain': 'lucide.dev',
defer: ''
}],
[ 'meta', {
property:"og:locale",
content:"en_US"
}],
[ 'meta', {
property:"og:type",
content:"website"
}],
[ 'meta', {
property:"og:site_name",
content: title,
}],
[ 'meta', {
property:"og:title",
content: socialTitle,
}],
[ 'meta', {
property:"og:description",
content: description
}],
[ 'meta', {
property:"og:url",
content:"https://lucide.dev"
}],
[ 'meta', {
property:"og:image",
content: "https://lucide.dev/og.png"
}],
[ 'meta', {
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: {
// https://vitepress.dev/reference/default-theme-config
logo: {
light: '/logo.light.svg',
dark: '/logo.dark.svg',
dark: '/logo.dark.svg'
},
nav: [
{ text: 'Icons', link: '/icons/' },
@@ -155,21 +110,21 @@ export default defineConfig({
sidebar,
socialLinks: [
{ icon: 'github', link: 'https://github.com/lucide-icons/lucide' },
{ icon: 'discord', link: 'https://discord.gg/EH6nSts' },
{ icon: 'discord', link: 'https://discord.gg/EH6nSts' }
],
footer: {
message: 'Released under the ISC License.',
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`,
copyright: `Copyright © ${new Date().getFullYear()} Lucide Contributors`
},
editLink: {
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path',
pattern: 'https://github.com/lucide-icons/lucide/edit/main/docs/:path'
},
carbonAds: {
code: 'CWYIC53U',
placement: 'lucidedev',
},
placement: 'lucidedev'
}
},
sitemap: {
hostname: 'https://lucide.dev/',
},
});
hostname: 'https://lucide.dev/'
}
})

View File

@@ -3,171 +3,87 @@
"order": 0,
"icon": "js",
"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": {
"order": 1,
"icon": "react",
"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": {
"order": 2,
"icon": "vue",
"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": {
"order": 3,
"icon": "vue-next",
"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": {
"order": 4,
"icon": "svelte",
"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": {
"order": 4,
"icon": "solid",
"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": {
"order": 5,
"icon": "preact",
"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": {
"order": 6,
"icon": "react-native",
"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": {
"order": 7,
"icon": "angular",
"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": {
"order": 8,
"icon": "svg",
"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": {
"order": 9,
"icon": "flutter",
"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" }
]
}
}

View File

@@ -1,48 +0,0 @@
[
{
"name": "Eric Fennis",
"title": "Creator of Lucide & Software engineer @nedap",
"image": "https://github.com/ericfennis.png?size=192",
"sponsor": "https://github.com/sponsors/ericfennis",
"socialLinks": [
{
"icon": "github",
"link": "https://github.com/ericfennis"
},
{
"icon": "x",
"link": "https://github.com/ericfennis"
}
]
},
{
"name": "Karsa Rigó",
"title": "Maintainer of Lucide & Software engineer @sztaki",
"image": "https://github.com/karsa-mistmere.png?size=192",
"socialLinks": [
{
"icon": "github",
"link": "https://github.com/karsa-mistmere"
},
{
"icon": "linkedin",
"link": "https://www.linkedin.com/in/karsamistmere"
}
]
},
{
"name": "jguddas",
"title": "Maintainer of Lucide & Software engineer @lego",
"image": "https://github.com/jguddas.png?size=192",
"socialLinks": [
{
"icon": "github",
"link": "https://github.com/jguddas"
},
{
"icon": "linkedin",
"link": "https://www.linkedin.com/in/jguddas"
}
]
}
]

View File

@@ -17,62 +17,21 @@ const Backdrop = ({ src, color = 'red', backdropString }: BackdropProps): JSX.El
patternUnits="userSpaceOnUse"
patternTransform="rotate(45 50 50)"
>
<line
stroke={color}
strokeWidth={0.1}
y2={1}
/>
<line
stroke={color}
strokeWidth={0.1}
y2={1}
/>
<line stroke={color} strokeWidth={0.1} y2={1} />
<line stroke={color} strokeWidth={0.1} y2={1} />
</pattern>
</defs>
<mask
id="svg-preview-backdrop-mask-outline"
maskUnits="userSpaceOnUse"
>
<g
stroke="#fff"
dangerouslySetInnerHTML={{ __html: backdropString }}
/>
<g
dangerouslySetInnerHTML={{ __html: src }}
strokeWidth={2.05}
/>
<mask id="svg-preview-backdrop-mask-outline" maskUnits="userSpaceOnUse">
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
<g dangerouslySetInnerHTML={{ __html: src }} strokeWidth={2.05} />
</mask>
<mask
id="svg-preview-backdrop-mask-fill"
maskUnits="userSpaceOnUse"
>
<g
stroke="#fff"
dangerouslySetInnerHTML={{ __html: backdropString }}
/>
<g
dangerouslySetInnerHTML={{ __html: src }}
strokeWidth={2.05}
/>
<g
strokeWidth={1.75}
dangerouslySetInnerHTML={{ __html: backdropString }}
/>
<mask id="svg-preview-backdrop-mask-fill" maskUnits="userSpaceOnUse">
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
<g dangerouslySetInnerHTML={{ __html: src }} strokeWidth={2.05} />
<g strokeWidth={1.75} dangerouslySetInnerHTML={{ __html: backdropString }} />
</mask>
<g
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 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>
<rect
x="0"

View File

@@ -10,11 +10,7 @@ const Grid = ({
strokeWidth: number;
radius: number;
} & PathProps<'stroke', 'strokeWidth'>) => (
<g
className="svg-preview-grid-group"
strokeLinecap="butt"
{...props}
>
<g className="svg-preview-grid-group" strokeLinecap="butt" {...props}>
<rect
className="svg-preview-grid-rect"
width={24 - props.strokeWidth}
@@ -25,29 +21,11 @@ const Grid = ({
fill={fill}
/>
<path
strokeDasharray={'0 0.1 ' + '0.1 0.15 '.repeat(11) + '0 0.15'}
strokeWidth={0.1}
d={
props.d ||
new Array(Math.floor(24 - 1))
.fill(null)
.map((_, i) => i)
.filter((i) => i % 3 !== 2)
.flatMap((i) => [
`M${props.strokeWidth} ${i + 1}h${24 - props.strokeWidth * 2}`,
`M${i + 1} ${props.strokeWidth}v${24 - props.strokeWidth * 2}`,
])
.join('')
}
/>
<path
d={
props.d ||
new Array(Math.floor(24 - 1))
.fill(null)
.map((_, i) => i)
.filter((i) => i % 3 === 2)
.flatMap((i) => [
.flatMap((_, i) => [
`M${props.strokeWidth} ${i + 1}h${24 - props.strokeWidth * 2}`,
`M${i + 1} ${props.strokeWidth}v${24 - props.strokeWidth * 2}`,
])
@@ -66,21 +44,15 @@ const Shadow = ({
paths: Path[];
} & PathProps<'stroke' | 'strokeWidth' | 'strokeOpacity', 'd'>) => {
const groupedPaths = Object.entries(
paths.reduce(
(groups, val) => {
const key = val.c.id;
groups[key] = [...(groups[key] || []), val];
return groups;
},
{} as Record<number, Path[]>,
),
paths.reduce((groups, val) => {
const key = val.c.id;
groups[key] = [...(groups[key] || []), val];
return groups;
}, {} as Record<number, Path[]>)
);
return (
<>
<g
className="svg-preview-shadow-mask-group"
{...props}
>
<g className="svg-preview-shadow-mask-group" {...props}>
{groupedPaths.map(([id, paths]) => (
<mask
id={`svg-preview-shadow-mask-${id}`}
@@ -89,15 +61,7 @@ const Shadow = ({
strokeWidth={props.strokeWidth}
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
d={paths
.flatMap(({ prev, next }) => [
@@ -110,16 +74,9 @@ const Shadow = ({
</mask>
))}
</g>
<g
className="svg-preview-shadow-group"
{...props}
>
<g className="svg-preview-shadow-group" {...props}>
{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
d={paths
@@ -137,16 +94,9 @@ const ColoredPath = ({
paths,
...props
}: { 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) => (
<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>
);
@@ -188,15 +138,7 @@ const ControlPath = ({
key={i}
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${next.x} ${next.y}h.01`} />
</mask>
@@ -204,10 +146,7 @@ const ControlPath = ({
);
})}
</g>
<g
className="svg-preview-control-path-group"
{...props}
>
<g className="svg-preview-control-path-group" {...props}>
{controlPaths.map(({ d, showMarker }, i) => (
<path
key={i}
@@ -216,33 +155,18 @@ const ControlPath = ({
/>
))}
</g>
<g
className="svg-preview-control-path-marker-group"
{...props}
>
<g className="svg-preview-control-path-marker-group" {...props}>
<path
d={controlPaths
.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('')}
/>
{controlPaths.map(({ d, prev, next, startMarker, endMarker }, i) => (
<React.Fragment key={i}>
{startMarker && (
<circle
cx={prev.x}
cy={prev.y}
r={pointSize / 2}
/>
)}
{endMarker && (
<circle
cx={next.x}
cy={next.y}
r={pointSize / 2}
/>
)}
{startMarker && <circle cx={prev.x} cy={prev.y} r={pointSize / 2} />}
{endMarker && <circle cx={next.x} cy={next.y} r={pointSize / 2} />}
</React.Fragment>
))}
</g>
@@ -258,16 +182,15 @@ const Radii = ({
any
>) => {
return (
<g
className="svg-preview-radii-group"
{...props}
>
<g className="svg-preview-radii-group" {...props}>
{paths.map(
({ c, prev, next, circle }, i) =>
circle && (
<React.Fragment key={i}>
{c.name !== 'circle' && (
<path d={`M${prev.x} ${prev.y} ${circle.x} ${circle.y} ${next.x} ${next.y}`} />
{c.name !== "circle" && (
<path
d={`M${prev.x} ${prev.y} ${circle.x} ${circle.y} ${next.x} ${next.y}`}
/>
)}
<circle
cy={circle.y}
@@ -277,7 +200,7 @@ const Radii = ({
stroke={
(Math.round(circle.x * 100) / 100) % 1 !== 0 ||
(Math.round(circle.y * 100) / 100) % 1 !== 0
? 'red'
? "red"
: undefined
}
/>
@@ -285,7 +208,11 @@ const Radii = ({
cy={circle.y}
cx={circle.x}
r={circle.r}
stroke={(Math.round(circle.r * 1000) / 1000) % 1 !== 0 ? 'red' : undefined}
stroke={
(Math.round(circle.r * 1000) / 1000) % 1 !== 0
? "red"
: undefined
}
/>
</React.Fragment>
),
@@ -303,28 +230,13 @@ const Handles = ({
>) => {
console.log(paths);
return (
<g
className="svg-preview-handles-group"
{...props}
>
<g className="svg-preview-handles-group" {...props}>
{paths.map(({ c, prev, next, cp1, cp2 }) => (
<>
{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 && (
<circle
cy={cp2.y}
cx={cp2.x}
r={0.25}
/>
)}
{cp2 && <circle cy={cp2.y} cx={cp2.x} r={0.25} />}
</>
))}
</g>
@@ -368,27 +280,9 @@ const SvgPreview = React.forwardRef<
{...props}
>
<style>{darkModeCss}</style>
{showGrid && (
<Grid
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}
/>
{showGrid && <Grid 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
paths={paths}
colors={[
@@ -413,19 +307,8 @@ const SvgPreview = React.forwardRef<
stroke="#777"
strokeOpacity={0.3}
/>
<ControlPath
radius={1}
paths={paths}
pointSize={1}
stroke="#fff"
strokeWidth={0.125}
/>
<Handles
paths={paths}
strokeWidth={0.12}
stroke="#FFF"
strokeOpacity={0.3}
/>
<ControlPath radius={1} paths={paths} pointSize={1} stroke="#fff" strokeWidth={0.125} />
<Handles paths={paths} strokeWidth={0.12} stroke="#FFF" strokeOpacity={0.3} />
{children}
</svg>
);

View File

@@ -16,7 +16,7 @@ export type Path = {
export type PathProps<
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>> &
Omit<
React.SVGProps<SVGPathElement & SVGRectElement & SVGCircleElement>,

View File

@@ -51,7 +51,7 @@ export const getCommands = (src: string) =>
getNodes(src)
.map(convertToPathNode)
.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) => {
@@ -60,10 +60,10 @@ export const getPaths = (src: string) => {
let prev: Point | undefined = undefined;
let start: Point | undefined = undefined;
const addPath = (
c: (typeof commands)[number],
c: typeof commands[number],
next: Point,
d?: string,
extras?: { circle?: Path['circle']; cp1?: Path['cp1']; cp2?: Path['cp2'] },
extras?: { circle?: Path['circle']; cp1?: Path['cp1']; cp2?: Path['cp2'] }
) => {
assert(prev);
paths.push({
@@ -153,7 +153,7 @@ export const getPaths = (src: string) => {
{
cp1: { x: prev.x - reflectedCp1.x, y: prev.y - reflectedCp1.y },
cp2: { x: c.x2, y: c.y2 },
},
}
);
break;
}
@@ -169,7 +169,7 @@ export const getPaths = (src: string) => {
assert(prev);
const backTrackCP = (
index: number,
currentPoint: { x: number; y: number },
currentPoint: { x: number; y: number }
): { x: number; y: number } => {
const previousCommand = commands[index - 1];
if (!previousCommand) {
@@ -211,7 +211,7 @@ export const getPaths = (src: string) => {
{
cp1: { x: prevCP.x, y: prevCP.y },
cp2: { x: prevCP.x, y: prevCP.y },
},
}
);
break;
}
@@ -226,13 +226,13 @@ export const getPaths = (src: string) => {
c.lArcFlag,
c.sweepFlag,
c.x,
c.y,
c.y
);
addPath(
c,
c,
`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;
}
@@ -253,7 +253,7 @@ export const arcEllipseCenter = (
fa: number,
fs: number,
x2: number,
y2: number,
y2: number
) => {
const phi = (a * Math.PI) / 180;
@@ -280,7 +280,7 @@ export const arcEllipseCenter = (
sign *
Math.sqrt(
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];

View File

@@ -1,34 +1,28 @@
import fs from 'fs';
import path from 'path';
import { Category, IconEntity } from '../theme/types';
import fs from "fs";
import path from "path";
import {Category, IconEntity} from "../theme/types";
const directory = path.join(process.cwd(), '../categories');
const directory = path.join(process.cwd(), "../categories");
export function getAllCategoryFiles(): Category[] {
const fileNames = fs.readdirSync(directory).filter((file) => path.extname(file) === '.json');
return fileNames.map((fileName) => {
const name = path.basename(fileName, '.json');
const fileContent = fs.readFileSync(path.join(directory, fileName), 'utf8');
const name = path.basename(fileName, '.json')
const fileContent = fs.readFileSync(path.join(directory, fileName), 'utf8')
const parsedFileContent = JSON.parse(fileContent);
const parsedFileContent = JSON.parse(fileContent)
return {
name,
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) => ({
...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)
}))
}

View File

@@ -1,18 +1,24 @@
import { bundledLanguages, type ThemeRegistration } from 'shikiji';
import { getHighlighter } from 'shikiji';
import {
bundledLanguages,
type ThemeRegistration
} from 'shikiji'
import {
getHighlighter,
} from 'shikiji'
type CodeExampleType = {
title: string;
language: string;
code: string;
}[];
title: string,
language: string,
code: string,
}[]
const getIconCodes = (): CodeExampleType => {
return [
{
language: 'html',
title: 'HTML',
code: `<i data-lucide="Name"></i>`,
code: `<i data-lucide="Name"></i>`
},
{
language: 'tsx',
@@ -103,37 +109,36 @@ import { LucideAngularModule, PascalCase } from 'lucide-angular';
<div class="icon-Name"></div>
`,
},
];
};
}
]
}
export type ThemeOptions =
| ThemeRegistration
| { light: ThemeRegistration; dark: ThemeRegistration };
| { light: ThemeRegistration; dark: ThemeRegistration }
const highLightCode = async (code: string, lang: string, active?: boolean) => {
const highlighter = await getHighlighter({
themes: ['github-light', 'github-dark'],
langs: Object.keys(bundledLanguages),
});
langs: Object.keys(bundledLanguages)
})
const highlightedCode = highlighter
.codeToHtml(code, {
lang,
themes: {
light: 'github-light',
dark: 'github-dark',
},
defaultColor: false,
})
.replace('shiki-themes', 'shiki-themes vp-code');
const highlightedCode = highlighter.codeToHtml(code, {
lang,
themes: {
light: 'github-light',
dark: 'github-dark'
},
defaultColor: false
}).replace('shiki-themes', 'shiki-themes vp-code')
return `<div class="language-${lang} ${active ? 'active' : ''}">
<button title="Copy Code" class="copy"></button>
<span class="lang">${lang}</span>
${highlightedCode}
</div>`;
};
</div>`
}
export default async function createCodeExamples() {
const codes = getIconCodes();
@@ -148,7 +153,7 @@ export default async function createCodeExamples() {
language: language,
code: codeString,
};
});
})
return Promise.all(codeExamplePromises);
}

View File

@@ -1,42 +1,38 @@
import { promises as fs, constants } from 'fs';
import path from 'path';
import yaml from 'js-yaml';
import yaml from 'js-yaml'
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 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 filePath = path.resolve(directory, filename);
const fileStat = await fs.lstat(filePath);
const packageJsons = await Promise.all(fileNames.map( async ({filename, directory}) => {
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');
if (await fileExist(jsonFilePath)) {
return JSON.parse(await fs.readFile(jsonFilePath, 'utf-8'));
}
const jsonFilePath = path.resolve(filePath, 'package.json')
if (await fileExist(jsonFilePath)) {
return JSON.parse(
await fs.readFile(jsonFilePath, 'utf-8')
)
}
const ymlFilePath = path.resolve(filePath, 'pubspec.yaml');
if (await fileExist(ymlFilePath)) {
return yaml.load(await fs.readFile(ymlFilePath, 'utf-8'));
}
const ymlFilePath = path.resolve(filePath, 'pubspec.yaml')
if(await fileExist(ymlFilePath)) {
return yaml.load(
await fs.readFile(ymlFilePath, 'utf-8')
);
}
return null;
}),
);
return null
}))
return packageJsons;
};
return packageJsons
}
export default fetchPackages;

View File

@@ -1,15 +1,17 @@
export type IconContent = [icon: string, src: string];
export type IconContent = [icon: string, src:string];
async function generateZip(icons: IconContent[]) {
const JSZip = (await import('jszip')).default;
const JSZip = (await import('jszip')).default
const zip = new JSZip();
const addingZipPromises = icons.map(([name, src]) => zip.file(`${name}.svg`, src));
const addingZipPromises = icons.map(([name, src]) =>
zip.file(`${name}.svg`, src),
);
await Promise.all(addingZipPromises);
await Promise.all(addingZipPromises)
return zip.generateAsync({ type: 'blob' });
}
export default generateZip;
export default generateZip

View File

@@ -1,15 +1,17 @@
import { createLucideIcon } from 'lucide-react/src/lucide-react';
import { type LucideProps, type IconNode } from 'lucide-react/src/createLucideIcon';
import { IconEntity } from '../theme/types';
import { createLucideIcon } from "lucide-react/src/lucide-react"
import { type LucideProps, type IconNode } from "lucide-react/src/createLucideIcon"
import { IconEntity } from "../theme/types"
import { renderToStaticMarkup } from 'react-dom/server';
import { IconContent } from './generateZip';
import { IconContent } from "./generateZip";
const getFallbackZip = (icons: IconEntity[], params: LucideProps) => {
return icons.map<IconContent>((icon) => {
const Icon = createLucideIcon(icon.name, icon.iconNode as IconNode);
const src = renderToStaticMarkup(<Icon {...params} />);
return [icon.name, src];
});
};
return icons
.map<IconContent>((icon) => {
const Icon = createLucideIcon(icon.name, icon.iconNode as IconNode)
const src = renderToStaticMarkup(<Icon {...params} />)
return [icon.name, src]
})
}
export default getFallbackZip;
export default getFallbackZip

View File

@@ -1,34 +1,34 @@
import fs from 'fs';
import path from 'path';
import { IconNodeWithKeys } from '../theme/types';
import iconNodes from '../data/iconNodes';
import releaseMeta from '../data/releaseMetaData.json';
import fs from "fs";
import path from "path";
import { IconNodeWithKeys } from "../theme/types";
import iconNodes from '../data/iconNodes'
import releaseMeta from "../data/releaseMetaData.json";
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 {
withChildKeys?: boolean;
withChildKeys?: boolean
}
export async function getData(name: string) {
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 iconNode = iconNodes[name];
const iconNode = iconNodes[name]
const releaseData = releaseMeta?.[name] ?? {
createdRelease: {
version: '0.0.0',
date: DATE_OF_FORK,
"createdRelease": {
"version": "0.0.0",
"date": DATE_OF_FORK
},
changedRelease: {
version: '0.0.0',
date: DATE_OF_FORK,
},
};
"changedRelease": {
"version": "0.0.0",
"date": DATE_OF_FORK
}
}
return {
name,
@@ -36,11 +36,11 @@ export async function getData(name: string) {
categories,
iconNode,
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);
return Promise.all(names.map((name) => getData(name)));

View File

@@ -1,31 +1,31 @@
import { DefaultTheme, UserConfig } from 'vitepress';
import { DefaultTheme, UserConfig } from "vitepress"
const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
guide: [
'guide':[
{
text: 'Introduction',
items: [
{ text: 'What is lucide?', link: '/guide/' },
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Comparison', link: '/guide/comparison' },
],
{ text: 'Comparison', link: '/guide/comparison' }
]
},
{
text: 'Basics',
items: [
{
text: 'Color',
link: '/guide/basics/color',
link: '/guide/basics/color'
},
{
text: 'Sizing',
link: '/guide/basics/sizing',
link: '/guide/basics/sizing'
},
{
text: 'Stroke width',
link: '/guide/basics/stroke-width',
link: '/guide/basics/stroke-width'
},
],
]
},
// TODO: Add this section
{
@@ -37,14 +37,14 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
// },
{
text: 'Global styling',
link: '/guide/advanced/global-styling',
link: '/guide/advanced/global-styling'
},
// {
// text: 'Animations',
// },
{
text: 'Filled icons',
link: '/guide/advanced/filled-icons',
link: '/guide/advanced/filled-icons'
},
// {
// text: 'Combining icons',
@@ -55,73 +55,75 @@ const sidebar: UserConfig<DefaultTheme.Config>['themeConfig']['sidebar'] = {
// {
// text: 'Auto importing'
// },
],
]
},
{
text: 'Packages',
items: [
{
text: 'Lucide',
link: '/guide/packages/lucide',
link: '/guide/packages/lucide'
},
{
text: 'Lucide React',
link: '/guide/packages/lucide-react',
link: '/guide/packages/lucide-react'
},
{
text: 'Lucide React Native',
link: '/guide/packages/lucide-react-native',
link: '/guide/packages/lucide-react-native'
},
{
text: 'Lucide Vue',
link: '/guide/packages/lucide-vue-next',
link: '/guide/packages/lucide-vue-next'
},
{
text: 'Lucide Svelte',
link: '/guide/packages/lucide-svelte',
link: '/guide/packages/lucide-svelte'
},
{
text: 'Lucide Solid',
link: '/guide/packages/lucide-solid',
link: '/guide/packages/lucide-solid'
},
{
text: 'Lucide Preact',
link: '/guide/packages/lucide-preact',
link: '/guide/packages/lucide-preact'
},
{
text: 'Lucide Angular',
link: '/guide/packages/lucide-angular',
link: '/guide/packages/lucide-angular'
},
{
text: 'Lucide Static',
link: '/guide/packages/lucide-static',
link: '/guide/packages/lucide-static'
},
],
]
},
{
text: 'Contributing',
items: [
{
text: 'Icon Design Principles',
link: '/guide/design/icon-design-guide',
link: '/guide/design/icon-design-guide'
},
{
text: 'Designing in Illustrator',
link: '/guide/design/illustrator-guide',
link: '/guide/design/illustrator-guide'
},
{
text: 'Designing in InkScape',
link: '/guide/design/inkscape-guide',
link: '/guide/design/inkscape-guide'
},
{
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
icons: [{ text: '', link: '/' }],
};
'icons': [
{ text: '', link: '/' },
],
}
export default sidebar;
export default sidebar

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed } from 'vue';
import { useRouter } from 'vitepress';
const { go } = useRouter()

View File

@@ -1,11 +1,11 @@
<template>
<div class="card-grid-flex">
<div class="grid">
<slot />
</div>
</template>
<style>
.card-grid-flex {
<style scoped>
.grid {
display: flex;
flex-wrap: wrap;
align-items: stretch;
@@ -15,20 +15,20 @@
margin: -8px;
}
.card-grid-flex > * {
.grid > * {
flex-basis: 100%;
box-sizing: border-box;
padding: 8px;
}
@media (min-width: 960px) {
.card-grid-flex > * {
.grid > * {
flex-basis: 50%;
}
}
@media (min-width: 1280px) {
.card-grid-flex > * {
.grid > * {
flex-basis: 33.33%;
}
}

View File

@@ -24,10 +24,40 @@ const headingElement = computed(() => `h${props.headingLevel}`)
font-size: 32px;
font-weight: bold;
text-align: center;
margin-bottom: 36px;
margin-bottom: 32px;
}
section {
margin-bottom: 96px;
}
.grid {
display: flex;
flex-wrap: wrap;
align-items: stretch;
justify-content: center;
align-content: space-evenly;
box-sizing: border-box;
margin: -8px;
}
.grid > * {
flex-basis: 100%;
box-sizing: border-box;
padding: 8px;
}
@media (min-width: 960px) {
.grid > * {
flex-basis: 50%;
}
}
@media (min-width: 1280px) {
.grid > * {
flex-basis: 33.33%;
}
}
</style>

View File

@@ -1,18 +1,16 @@
export default {
async load() {
const version = await fetch('https://api.github.com/repos/lucide-icons/lucide/releases/latest')
.then((res) => {
if (res.ok) {
const releaseData = res.json() as Promise<{ tag_name: string }>;
const version = await fetch('https://api.github.com/repos/lucide-icons/lucide/releases/latest').then(res => {
if (res.ok) {
const releaseData = res.json() as Promise<{ tag_name: string }>
return releaseData;
}
return null;
})
.then((res) => res.tag_name);
return releaseData
}
return null
}).then(res => res.tag_name)
return {
version,
};
},
};
version
}
}
}

View File

@@ -1,17 +1,16 @@
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 {
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 {
icons: randomIcons,
iconsCount: icons.length,
};
},
};
}
}
}

View File

@@ -28,6 +28,8 @@ function insert() {
const replaceIndex = random(0, 48)
const newIcon = getRandomNewIcon()
// items.value.splice(replaceIndex, 0, newIcon);
items.value[replaceIndex] = newIcon
}
@@ -74,6 +76,7 @@ onBeforeUnmount(() => {
<style scoped>
.card-wrapper {
/* padding: 0 24px; */
margin-left: auto;
margin-bottom: auto;
margin-top: 48px;
@@ -84,10 +87,13 @@ onBeforeUnmount(() => {
border-radius: 8px;
width: 100%;
height:100%;
/* box-shadow: var(--vp-shadow-2); */
max-height: 220px;
max-width: 560px;
margin: 0 auto;
position: relative;
/* max-height: 240px; */
/* margin-top: 96px; */
}
.card-grid {
@@ -101,6 +107,7 @@ onBeforeUnmount(() => {
max-width: 512px;
overflow: hidden;
position: relative;
/* white-space: nowrap; */
}
.list-enter-active {

View File

@@ -47,7 +47,7 @@ export default {
logo: '/framework-logos/flutter.svg',
label: 'Lucide documentation for Flutter',
},
],
};
},
};
]
}
}
}

View File

@@ -1,6 +1,5 @@
<script setup lang="ts">
import HomeContainer from './HomeContainer.vue'
import HomeSectionTitle from './HomeSectionTitle.vue'
import { useRouter } from 'vitepress';
import { data } from './HomePackagesSection.data'
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue';
@@ -10,7 +9,7 @@ const { go } = useRouter()
<template>
<HomeContainer>
<HomeSectionTitle>Available For:</HomeSectionTitle>
<h2 class="section-title">Available For:</h2>
<div class="packages-list">
<a
v-for="{ name, logo } in data.packages"
@@ -35,6 +34,14 @@ const { go } = useRouter()
</template>
<style scoped>
.section-title {
color: var(--vp-c-text-2);
font-weight: 500;
line-height: 32px;
font-size: 16px;
text-align: center;
margin-bottom: 16px;
}
.packages-list {
display: flex;
flex-wrap: wrap;

View File

@@ -1,26 +0,0 @@
<script setup lang="ts">
import { computed } from 'vue';
const props = defineProps<{
headingLevel: 1 | 2 | 3 | 4 | 5 | 6,
}>()
const headingElement = computed(() => `h${props.headingLevel ?? 2}`)
</script>
<template>
<component :is="headingElement" class="section-title">
<slot />
</component>
</template>
<style scoped>
.section-title {
color: var(--vp-c-text-2);
font-weight: 500;
line-height: 32px;
font-size: 16px;
text-align: center;
margin-bottom: 16px;
}
</style>

View File

@@ -1,46 +0,0 @@
<script setup lang="ts">
import Card from '../base/Card.vue'
import HomeSectionTitle from './HomeSectionTitle.vue'
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue'
</script>
<template>
<HomeSectionTitle :headingLevel="3">
Sponsor the Lucide maintainers
</HomeSectionTitle>
<Card class="sponsor-card">
<img
src="/open-collective.png"
alt="Open Collective logo"
width="242"
height="42"
/>
<VPButton
href="https://opencollective.com/lucide-icons"
class="sponsor-button"
text="Become a sponsor"
/>
</Card>
</template>
<style scoped>
.sponsor-card {
margin: 0 auto;
max-width: 500px;
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
}
.sponsor-button {
margin: auto 0;
}
@media (min-width: 640px) {
.sponsor-card {
flex-direction: row;
justify-content: space-between;
}
}
</style>

View File

@@ -1,91 +0,0 @@
<script setup lang="ts">
import { useData } from 'vitepress';
import HomeContainer from './HomeContainer.vue'
import GridSection from '../base/GridSection.vue'
import TeamMemberCard, { TeamMember } from './TeamMemberCard.vue'
import teamData from '../../../data/teamData.json'
import HomeSponsorCard from './HomeSponsorCard.vue';
import VPDocAsideCarbonAds from 'vitepress/dist/client/theme-default/components/VPDocAsideCarbonAds.vue'
const { theme } = useData()
</script>
<template>
<HomeContainer>
<GridSection
title="Meet the team"
:headingLevel="2"
class="team-members"
>
<TeamMemberCard
v-for="teamMember in (teamData as TeamMember[])"
v-bind="teamMember"
/>
</GridSection>
<HomeSponsorCard />
<VPDocAsideCarbonAds
:carbon-ads="theme.carbonAds"
class="ad-card"
/>
</HomeContainer>
</template>
<style scoped>
.team-members {
gap: 24px;
margin-top: 48px;
margin-bottom: 48px;
}
@media (min-width: 640px) {
.team-members :deep(.card-grid > *) {
flex-basis: 50%;
}
}
@media (min-width: 768px) {
.team-members :deep(.card-grid > *) {
flex-basis: 33.33%;
}
}
.ad-card {
margin: 32px auto 0;
width: 100%;;
max-width: 500px;
display: flex;
flex-direction: row;
justify-content: space-between;
display: none;
}
@media (min-width: 960px) {
.ad-card {
display: block;
}
}
.ad-card :deep(.VPCarbonAds) {
width: 100%;
text-align: left;
min-height: auto;
}
.ad-card :deep(.VPCarbonAds .carbon-wrap) {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 24px;
}
.ad-card :deep(.VPCarbonAds .carbon-text) {
padding-top: 0;
}
.ad-card :deep(.VPCarbonAds .carbon-poweredby) {
text-align: right;
margin-top: -24px;
}
</style>

View File

@@ -1,91 +0,0 @@
<script lang="ts">
export interface TeamMember {
name: string
title: string
image: string
sponsor: string
socialLinks: DefaultTheme.SocialLink[]
}
</script>
<script setup lang="ts">
import { DefaultTheme } from 'vitepress';
import Card from '../base/Card.vue'
import VPButton from 'vitepress/dist/client/theme-default/components/VPButton.vue'
import VPSocialLinks from 'vitepress/dist/client/theme-default/components/VPSocialLinks.vue'
defineProps<TeamMember>()
</script>
<template>
<div>
<Card class="member-card">
<img :src="image" :alt="name" class="member-image"/>
<h3 class="member-name">
{{name}}
</h3>
<p class="member-title">
{{title}}
</p>
<div class="member-links">
<VPButton
v-if="sponsor"
:href="sponsor"
text="Sponsor"
theme="sponsor"
class="sponsor-button"
size="medium"
/>
<VPSocialLinks
:links="socialLinks"
/>
</div>
</Card>
</div>
</template>
<style scoped>
.member-card {
flex-basis: 100%;
height:100%;
}
.member-image {
width: 64px;
height: 64px;
border-radius: 32px;
margin: 0 auto;
background-color: var(--vp-c-bg);
}
.member-name {
text-align: center;
margin-top: 16px;
font-size: 21px;
font-weight: 500;
color: var(--textColor);
}
.member-title {
flex-grow: 1;
padding-top: 8px;
line-height: 24px;
font-size: 14px;
font-weight: 500;
color: var(--vp-c-text-2);
text-align: center;
margin-bottom: 16px;;
}
.sponsor-button {
width: auto;
}
.member-links {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
}
</style>

View File

@@ -1,83 +0,0 @@
<script setup lang="ts">
import { useData } from 'vitepress';
import { useSessionStorage } from '@vueuse/core';
import IconButton from '../base/IconButton.vue';
import VPDocAsideCarbonAds from 'vitepress/dist/client/theme-default/components/VPDocAsideCarbonAds.vue'
import { x } from '../../../data/iconNodes'
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
const { theme } = useData()
const showAd = useSessionStorage('show-carbon-ads',true)
defineProps<{
drawerOpen: boolean
}>()
const CloseIcon = createLucideIcon('Close', x)
</script>
<template>
<div
:class="{
'drawer-open': drawerOpen,
'hide-ad': !showAd
}"
class="floating-ad"
v-if="theme.carbonAds"
>
<IconButton @click="showAd = false" class="hide-button">
<component :is="CloseIcon" :size="20" absoluteStrokeWidth />
</IconButton>
<VPDocAsideCarbonAds
:carbon-ads="theme.carbonAds"
/>
</div>
</template>
<style scoped>
.floating-ad {
display: none;
position: fixed;
bottom: 32px;
width: 224px;
right: 32px;
transition: opacity 0.5s, transform 0.25s ease;
}
.floating-ad.drawer-open {
transform: translateY(-288px);
}
.floating-ad.hide-ad {
transform: translateX(224px);
opacity: 0;
}
.floating-ad.drawer-open.hide-ad {
transform: translateY(-288px) translateX(224px);
}
.floating-ad.drawer-open, .floating-ad.hide-ad {
transition: opacity 0.25s, transform 0.5s cubic-bezier(0.19, 1, 0.22, 1);
}
@media (min-width: 1280px) {
.floating-ad {
display: block;
}
}
@media (min-width: 1440px) {
.floating-ad {
right: calc(((100% - (var(--vp-layout-max-width) - var(--vp-sidebar-width))) - 272px) / 2);
}
}
.hide-button {
padding: 4px;
position: absolute;
top: 8px;
right: 8px;
background-color: transparent;
}
</style>

View File

@@ -1,15 +1,16 @@
import { getAllData } from '../../../lib/icons';
import { getAllCategoryFiles, mapCategoryIconCount } from '../../../lib/categories';
import iconsMetaData from '../../../data/iconMetaData';
import iconsMetaData from '../../../data/iconMetaData'
export default {
async load() {
let categories = getAllCategoryFiles();
let categories = getAllCategoryFiles()
categories = mapCategoryIconCount(categories, Object.values(iconsMetaData));
categories = mapCategoryIconCount(categories, Object.values(iconsMetaData))
return {
categories,
};
},
};
}
}
}

View File

@@ -1,15 +1,13 @@
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { ref, computed } from 'vue'
import { useData } from 'vitepress'
import VPLink from 'vitepress/dist/client/theme-default/components/VPLink.vue'
import { isActive } from 'vitepress/dist/client/shared'
import { useActiveAnchor } from '../../composables/useActiveAnchor'
import { data } from './CategoryList.data'
import CategoryListItem from './CategoryListItem.vue'
import { useCategoryView } from '../../composables/useCategoryView'
const { page } = useData()
const { categoryCounts } = useCategoryView();
const categoriesIsActive = computed(() => {
return isActive(page.value.relativePath, '/icons/categories');
@@ -27,21 +25,14 @@ const headers = computed(() => {
level: 2,
link: `${linkPrefix}#${name}`,
title,
iconCount: categoryCounts.value[name] ?? iconCount,
name
iconCount
}))
})
const container = ref()
const marker = ref()
const { setActiveLinkDebounced } = useActiveAnchor(container, marker)
watch(headers, () => {
setTimeout(() => {
setActiveLinkDebounced()
}, 200)
})
useActiveAnchor(container, marker)
</script>
<template>

Some files were not shown because too many files have changed in this diff Show More