mirror of
https://github.com/lucide-icons/lucide.git
synced 2025-12-21 20:29:21 +01:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95a7d8648f | ||
|
|
b07eb8c00d | ||
|
|
40cb396a6c | ||
|
|
87ab0bfb62 | ||
|
|
c4f50417d5 | ||
|
|
0ca1b98689 | ||
|
|
7ce35bac34 | ||
|
|
5ec34cb249 | ||
|
|
313b46ecc1 | ||
|
|
367f89ef1f | ||
|
|
32ba19d591 |
@@ -9,10 +9,10 @@
|
|||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
>
|
>
|
||||||
<line x1="5" y1="8" x2="11" y2="14" />
|
<path d="M5 8l6 6" />
|
||||||
<path d="M4 14l6-6 2-3" />
|
<path d="M4 14l6-6 2-3" />
|
||||||
<line x1="2" y1="5" x2="14" y2="5" />
|
<path d="M2 5h12" />
|
||||||
<line x1="7" y1="2" x2="8" y2="2" />
|
<path d="M7 2h1" />
|
||||||
<path d="M22 21l-5-10-5 10" />
|
<path d="M22 22l-5-10-5 10" />
|
||||||
<line x1="14" y1="17" x2="20" y2="17" />
|
<path d="M14 18h6" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 433 B After Width: | Height: | Size: 363 B |
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "lucide",
|
"name": "lucide",
|
||||||
"description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
|
"description": "Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
|
||||||
"version": "0.13.0",
|
"version": "0.14.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"homepage": "https://lucide.dev",
|
"homepage": "https://lucide.dev",
|
||||||
"bugs": "https://github.com/lucide-icons/lucide/issues",
|
"bugs": "https://github.com/lucide-icons/lucide/issues",
|
||||||
|
|||||||
25
packages/lucide-figma/README.md
Normal file
25
packages/lucide-figma/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Lucide Figma plugin
|
||||||
|
|
||||||
|
A Figma plugin for using Lucide Icons
|
||||||
|
|
||||||
|
## Local development
|
||||||
|
|
||||||
|
1. Install the dependencies
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build the plugin
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn watch
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Open the [Figma desktop app](https://www.figma.com/downloads/)
|
||||||
|
|
||||||
|
4. Go to `Menu > Plugins > Development > New Plugin...`
|
||||||
|
|
||||||
|
5. Choose `lucide/packages/lucide-figma/manifest.json`
|
||||||
|
|
||||||
|
6. Run the plugin by going to `Menu > Plugins > Development > Lucide Icons`
|
||||||
BIN
packages/lucide-figma/cover.png
Normal file
BIN
packages/lucide-figma/cover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 127 KiB |
675
packages/lucide-figma/figma.d.ts
vendored
Normal file
675
packages/lucide-figma/figma.d.ts
vendored
Normal file
@@ -0,0 +1,675 @@
|
|||||||
|
// Global variable with Figma's plugin API.
|
||||||
|
declare const figma: PluginAPI
|
||||||
|
declare const __html__: string
|
||||||
|
|
||||||
|
interface PluginAPI {
|
||||||
|
readonly currentPage: PageNode
|
||||||
|
|
||||||
|
// Root of the current Figma document.
|
||||||
|
readonly root: DocumentNode
|
||||||
|
|
||||||
|
// API for accessing viewport information.
|
||||||
|
readonly viewport: ViewportAPI
|
||||||
|
|
||||||
|
// call this once your plugin is finished executing.
|
||||||
|
closePlugin(): void
|
||||||
|
|
||||||
|
// Command that the user chose through menu when launching the plugin.
|
||||||
|
readonly command: string
|
||||||
|
|
||||||
|
// Finds a node by its id. If not found, returns null.
|
||||||
|
getNodeById(id: string): BaseNode | null
|
||||||
|
|
||||||
|
// Finds a style by its id. If not found, returns null.
|
||||||
|
getStyleById(id: string): BaseStyle | null
|
||||||
|
|
||||||
|
// Access browser APIs and/or show UI to the user.
|
||||||
|
showUI(html: string, options?: ShowUIOptions): void
|
||||||
|
readonly ui: UIAPI
|
||||||
|
|
||||||
|
// Lets you store persistent data on the user's local machine
|
||||||
|
readonly clientStorage: ClientStorageAPI
|
||||||
|
|
||||||
|
// This value is returned when a property is in a "mixed" state.
|
||||||
|
// In order to check if a property is in a mixed state, always
|
||||||
|
// compare directly to this value. I.e.
|
||||||
|
// `if (node.cornerRadius === figma.mixed) { ... }`
|
||||||
|
mixed: symbol
|
||||||
|
|
||||||
|
// Creates new nodes. Nodes will start off inserted
|
||||||
|
// into the current page.
|
||||||
|
// To move them elsewhere use `appendChild` or `insertChild`
|
||||||
|
createRectangle(): RectangleNode
|
||||||
|
createLine(): LineNode
|
||||||
|
createEllipse(): EllipseNode
|
||||||
|
createPolygon(): PolygonNode
|
||||||
|
createStar(): StarNode
|
||||||
|
createVector(): VectorNode
|
||||||
|
createText(): TextNode
|
||||||
|
createBooleanOperation(): BooleanOperationNode
|
||||||
|
createFrame(): FrameNode
|
||||||
|
createComponent(): ComponentNode
|
||||||
|
createPage(): PageNode
|
||||||
|
createSlice(): SliceNode
|
||||||
|
|
||||||
|
// Creates styles. A style's id can be assigned to
|
||||||
|
// node properties like textStyleId, fillStyleId, etc.
|
||||||
|
createPaintStyle(): PaintStyle
|
||||||
|
createTextStyle(): TextStyle
|
||||||
|
createEffectStyle(): EffectStyle
|
||||||
|
createGridStyle(): GridStyle
|
||||||
|
|
||||||
|
// These let you insert stuff from the team library if you have the key
|
||||||
|
importComponentByKeyAsync(key: string): Promise<ComponentNode>
|
||||||
|
importStyleByKeyAsync(key: string): Promise<BaseStyle>
|
||||||
|
|
||||||
|
// Return all fonts currently supported for use with the "fontName" property
|
||||||
|
listAvailableFontsAsync(): Promise<Font[]>
|
||||||
|
|
||||||
|
// You must await the promise returned here before being able to use "fontName"
|
||||||
|
loadFontAsync(fontName: FontName): Promise<void>
|
||||||
|
|
||||||
|
// Creates node from an SVG string.
|
||||||
|
createNodeFromSvg(svg: string): FrameNode
|
||||||
|
|
||||||
|
// Creates an Image object using the provided file contents.
|
||||||
|
createImage(data: Uint8Array): Image
|
||||||
|
|
||||||
|
// Groups every node in `nodes` under a new group.
|
||||||
|
group(nodes: ReadonlyArray<BaseNode>, parent: BaseNode & ChildrenMixin, index?: number): FrameNode
|
||||||
|
|
||||||
|
// Flattens every node in `nodes` into a single vector network.
|
||||||
|
flatten(nodes: ReadonlyArray<BaseNode>, parent?: BaseNode & ChildrenMixin, index?: number): VectorNode
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ClientStorageAPI {
|
||||||
|
// This stores information in the browser, not on the server. It's similar to localStorage, but is
|
||||||
|
// asynchronous, and allows storing objects, arrays, strings, numbers, booleans, null, undefined and Uint8Arrays.
|
||||||
|
getAsync(key: string): Promise<any | undefined>
|
||||||
|
setAsync(key: string, value: any): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShowUIOptions = {
|
||||||
|
visible?: boolean, // defaults to true
|
||||||
|
width?: number, // defaults to 300
|
||||||
|
height?: number, // defaults to 200
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UIAPI {
|
||||||
|
show(): void
|
||||||
|
hide(): void
|
||||||
|
resize(width: number, height: number): void
|
||||||
|
close(): void
|
||||||
|
|
||||||
|
// Sends a message to the iframe.
|
||||||
|
postMessage(pluginMessage: any): void
|
||||||
|
|
||||||
|
// Registers a callback for messages sent by the iframe.
|
||||||
|
onmessage: ((pluginMessage: any) => void) | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ViewportAPI {
|
||||||
|
center: { x: number, y: number }
|
||||||
|
|
||||||
|
// 1.0 means 100% zoom, 0.5 means 50% zoom.
|
||||||
|
zoom: number
|
||||||
|
|
||||||
|
// Adjust the viewport such that it shows the provided nodes.
|
||||||
|
scrollAndZoomIntoView(nodes: ReadonlyArray<BaseNode>)
|
||||||
|
}
|
||||||
|
|
||||||
|
// manifest.json format
|
||||||
|
interface ManifestJson {
|
||||||
|
// Name of the plugin.
|
||||||
|
name: string
|
||||||
|
|
||||||
|
// Version of the runtime that the plugin uses, e.g. '0.5.0'.
|
||||||
|
version: string
|
||||||
|
|
||||||
|
// The file name that contains the plugin code.
|
||||||
|
script: string
|
||||||
|
|
||||||
|
// The file name that contains the html code made available in script.
|
||||||
|
html?: string
|
||||||
|
|
||||||
|
// Shell command to be executed before the contents of the `html` and `script` files are read.
|
||||||
|
build?: string
|
||||||
|
|
||||||
|
// Menu items to show up in UI.
|
||||||
|
menu?: ManifestMenuItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ManifestMenuItem =
|
||||||
|
// Clickable menu item.
|
||||||
|
{ name: string, command: string } |
|
||||||
|
// Separator
|
||||||
|
{ separator: true } |
|
||||||
|
// Submenu
|
||||||
|
{ name: string, menu: ManifestMenuItem[] }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Values
|
||||||
|
|
||||||
|
// These are the top two rows of a 3x3 matrix. This is enough to represent
|
||||||
|
// translation, rotation, and skew.
|
||||||
|
type Transform = [
|
||||||
|
[number, number, number],
|
||||||
|
[number, number, number]
|
||||||
|
]
|
||||||
|
|
||||||
|
interface Vector {
|
||||||
|
readonly x: number
|
||||||
|
readonly y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RGB {
|
||||||
|
readonly r: number
|
||||||
|
readonly g: number
|
||||||
|
readonly b: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RGBA {
|
||||||
|
readonly r: number
|
||||||
|
readonly g: number
|
||||||
|
readonly b: number
|
||||||
|
readonly a: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FontName {
|
||||||
|
readonly family: string
|
||||||
|
readonly style: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ArcData {
|
||||||
|
readonly startingAngle: number
|
||||||
|
readonly endingAngle: number
|
||||||
|
readonly innerRadius: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ShadowEffect {
|
||||||
|
readonly type: "DROP_SHADOW" | "INNER_SHADOW"
|
||||||
|
readonly color: RGBA
|
||||||
|
readonly offset: Vector
|
||||||
|
readonly radius: number
|
||||||
|
readonly visible: boolean
|
||||||
|
readonly blendMode: BlendMode
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BlurEffect {
|
||||||
|
readonly type: "LAYER_BLUR" | "BACKGROUND_BLUR"
|
||||||
|
readonly radius: number
|
||||||
|
readonly visible: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
type Effect = ShadowEffect | BlurEffect
|
||||||
|
|
||||||
|
type ConstraintType = "MIN" | "CENTER" | "MAX" | "STRETCH" | "SCALE"
|
||||||
|
|
||||||
|
interface Constraints {
|
||||||
|
readonly horizontal: ConstraintType
|
||||||
|
readonly vertical: ConstraintType
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ColorStop {
|
||||||
|
readonly position: number
|
||||||
|
readonly color: RGBA
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SolidPaint {
|
||||||
|
readonly type: "SOLID"
|
||||||
|
readonly color: RGB
|
||||||
|
|
||||||
|
readonly visible?: boolean
|
||||||
|
readonly opacity?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GradientPaint {
|
||||||
|
readonly type: "GRADIENT_LINEAR" | "GRADIENT_RADIAL" | "GRADIENT_ANGULAR" | "GRADIENT_DIAMOND"
|
||||||
|
readonly gradientTransform: Transform
|
||||||
|
readonly gradientStops: ReadonlyArray<ColorStop>
|
||||||
|
|
||||||
|
readonly visible?: boolean
|
||||||
|
readonly opacity?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImagePaint {
|
||||||
|
readonly type: "IMAGE"
|
||||||
|
readonly scaleMode: "FILL" | "FIT" | "CROP" | "TILE"
|
||||||
|
readonly image: Image | null
|
||||||
|
readonly imageTransform?: Transform // setting for "CROP"
|
||||||
|
readonly scalingFactor?: number // setting for "TILE"
|
||||||
|
|
||||||
|
readonly visible?: boolean
|
||||||
|
readonly opacity?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type Paint = SolidPaint | GradientPaint | ImagePaint
|
||||||
|
|
||||||
|
interface Guide {
|
||||||
|
readonly axis: "X" | "Y"
|
||||||
|
readonly offset: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RowsColsLayoutGrid {
|
||||||
|
readonly pattern: "ROWS" | "COLUMNS"
|
||||||
|
readonly alignment: "MIN" | "STRETCH" | "CENTER"
|
||||||
|
readonly gutterSize: number
|
||||||
|
|
||||||
|
readonly count: number // Infinity when "Auto" is set in the UI
|
||||||
|
readonly sectionSize?: number // Not set for alignment: "STRETCH"
|
||||||
|
readonly offset?: number // Not set for alignment: "CENTER"
|
||||||
|
|
||||||
|
readonly visible?: boolean
|
||||||
|
readonly color?: RGBA
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GridLayoutGrid {
|
||||||
|
readonly pattern: "GRID"
|
||||||
|
readonly sectionSize: number
|
||||||
|
|
||||||
|
readonly visible?: boolean
|
||||||
|
readonly color?: RGBA
|
||||||
|
}
|
||||||
|
|
||||||
|
type LayoutGrid = RowsColsLayoutGrid | GridLayoutGrid
|
||||||
|
|
||||||
|
interface ExportSettingsImage {
|
||||||
|
format: "JPG" | "PNG"
|
||||||
|
contentsOnly?: boolean // defaults to true
|
||||||
|
suffix?: string
|
||||||
|
constraint?: { // defaults to unscaled ({ type: "SCALE", value: 1 })
|
||||||
|
type: "SCALE" | "WIDTH" | "HEIGHT"
|
||||||
|
value: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExportSettingsSVG {
|
||||||
|
format: "SVG"
|
||||||
|
contentsOnly?: boolean // defaults to true
|
||||||
|
suffix?: string
|
||||||
|
svgOutlineText?: boolean // defaults to true
|
||||||
|
svgIdAttribute?: boolean // defaults to false
|
||||||
|
svgSimplifyStroke?: boolean // defaults to true
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExportSettingsPDF {
|
||||||
|
format: "PDF"
|
||||||
|
contentsOnly?: boolean // defaults to true
|
||||||
|
suffix?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExportSettings = ExportSettingsImage | ExportSettingsSVG | ExportSettingsPDF
|
||||||
|
|
||||||
|
type WindingRule = "NONZERO" | "EVENODD"
|
||||||
|
|
||||||
|
interface VectorVertex {
|
||||||
|
readonly x: number
|
||||||
|
readonly y: number
|
||||||
|
readonly strokeCap?: StrokeCap
|
||||||
|
readonly strokeJoin?: StrokeJoin
|
||||||
|
readonly cornerRadius?: number
|
||||||
|
readonly handleMirroring?: HandleMirroring
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VectorSegment {
|
||||||
|
readonly start: number
|
||||||
|
readonly end: number
|
||||||
|
readonly tangentStart?: Vector // Defaults to { x: 0, y: 0 }
|
||||||
|
readonly tangentEnd?: Vector // Defaults to { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VectorRegion {
|
||||||
|
readonly windingRule: WindingRule
|
||||||
|
readonly loops: ReadonlyArray<ReadonlyArray<number>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VectorNetwork {
|
||||||
|
readonly vertices: ReadonlyArray<VectorVertex>
|
||||||
|
readonly segments: ReadonlyArray<VectorSegment>
|
||||||
|
readonly regions?: ReadonlyArray<VectorRegion> // Defaults to []
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VectorPath {
|
||||||
|
// Similar to the svg fill-rule
|
||||||
|
// "NONE" means an open path won't have a fill
|
||||||
|
readonly windingRule: WindingRule | "NONE"
|
||||||
|
readonly data: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type VectorPaths = ReadonlyArray<VectorPath>
|
||||||
|
|
||||||
|
interface NumberWithUnits {
|
||||||
|
readonly value: number
|
||||||
|
readonly units: "PIXELS" | "PERCENT"
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlendMode =
|
||||||
|
"PASS_THROUGH" |
|
||||||
|
"NORMAL" |
|
||||||
|
"DARKEN" |
|
||||||
|
"MULTIPLY" |
|
||||||
|
"LINEAR_BURN" |
|
||||||
|
"COLOR_BURN" |
|
||||||
|
"LIGHTEN" |
|
||||||
|
"SCREEN" |
|
||||||
|
"LINEAR_DODGE" |
|
||||||
|
"COLOR_DODGE" |
|
||||||
|
"OVERLAY" |
|
||||||
|
"SOFT_LIGHT" |
|
||||||
|
"HARD_LIGHT" |
|
||||||
|
"DIFFERENCE" |
|
||||||
|
"EXCLUSION" |
|
||||||
|
"HUE" |
|
||||||
|
"SATURATION" |
|
||||||
|
"COLOR" |
|
||||||
|
"LUMINOSITY"
|
||||||
|
|
||||||
|
interface Font {
|
||||||
|
fontName: FontName
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Mixins
|
||||||
|
|
||||||
|
interface BaseNodeMixin {
|
||||||
|
readonly id: string
|
||||||
|
readonly parent: (BaseNode & ChildrenMixin) | null
|
||||||
|
name: string
|
||||||
|
visible: boolean
|
||||||
|
locked: boolean
|
||||||
|
removed: boolean
|
||||||
|
toString(): string
|
||||||
|
remove(): void
|
||||||
|
|
||||||
|
// Attach custom data to a node. Only your plugin will be able to read this.
|
||||||
|
getPluginData(key: string): string
|
||||||
|
setPluginData(key: string, value: string): void
|
||||||
|
|
||||||
|
// Attach custom data to a node. All plugins will be able to read this.
|
||||||
|
// Namespace is a string that must be at least 3 alphanumeric characters, and should
|
||||||
|
// be a name related to your plugin. This is a mandatory argument to avoid multiple
|
||||||
|
// multiple plugins adding keys like "data" and colliding with each other. Other
|
||||||
|
// plugins will still be able to read shared plugin data as long as they know the
|
||||||
|
// namespace you use.
|
||||||
|
getSharedPluginData(namespace: string, key: string): string
|
||||||
|
setSharedPluginData(namespace: string, key: string, value: string): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChildrenMixin {
|
||||||
|
// Sorted back-to-front. I.e. the top-most child is last in this array.
|
||||||
|
readonly children: ReadonlyArray<BaseNode>
|
||||||
|
|
||||||
|
// Adds to the end of the .children array. I.e. visually on top of all other
|
||||||
|
// children.
|
||||||
|
appendChild(child: BaseNode): void
|
||||||
|
|
||||||
|
insertChild(index: number, child: BaseNode): void
|
||||||
|
findAll(callback?: (node: BaseNode) => boolean): ReadonlyArray<BaseNode>
|
||||||
|
findOne(callback: (node: BaseNode) => boolean): BaseNode | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LayoutMixin {
|
||||||
|
readonly absoluteTransform: Transform
|
||||||
|
relativeTransform: Transform
|
||||||
|
x: number // The same as "relativeTransform[0][2]"
|
||||||
|
y: number // The same as "relativeTransform[1][2]"
|
||||||
|
rotation: number // The angle of the x axis of "relativeTransform" in degrees. Returns values from -180 to 180.
|
||||||
|
|
||||||
|
readonly size: Vector
|
||||||
|
readonly width: number // The same as "size.x"
|
||||||
|
readonly height: number // The same as "size.y"
|
||||||
|
|
||||||
|
// Resizes the node. If children of the node has constraints, it applies those constraints
|
||||||
|
// width and height must be >= 0.01
|
||||||
|
resize(width: number, height: number): void
|
||||||
|
|
||||||
|
// Resizes the node. Children of the node are never resized, even if those children have
|
||||||
|
// constraints. width and height must be >= 0.01
|
||||||
|
resizeWithoutConstraints(width: number, height: number): void
|
||||||
|
|
||||||
|
constraints: Constraints
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BlendMixin {
|
||||||
|
opacity: number
|
||||||
|
blendMode: BlendMode
|
||||||
|
isMask: boolean
|
||||||
|
effects: ReadonlyArray<Effect>
|
||||||
|
effectStyleId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FrameMixin {
|
||||||
|
backgrounds: ReadonlyArray<Paint>
|
||||||
|
layoutGrids: ReadonlyArray<LayoutGrid>
|
||||||
|
clipsContent: boolean
|
||||||
|
guides: ReadonlyArray<Guide>
|
||||||
|
gridStyleId: string
|
||||||
|
backgroundStyleId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type StrokeCap = "NONE" | "ROUND" | "SQUARE" | "ARROW_LINES" | "ARROW_EQUILATERAL"
|
||||||
|
type StrokeJoin = "MITER" | "BEVEL" | "ROUND"
|
||||||
|
type HandleMirroring = "NONE" | "ANGLE" | "ANGLE_AND_LENGTH"
|
||||||
|
|
||||||
|
interface GeometryMixin {
|
||||||
|
fills: ReadonlyArray<Paint> | symbol // This can return figma.mixed on TEXT nodes
|
||||||
|
strokes: ReadonlyArray<Paint>
|
||||||
|
strokeWeight: number
|
||||||
|
strokeAlign: "CENTER" | "INSIDE" | "OUTSIDE"
|
||||||
|
strokeCap: StrokeCap | symbol // This can return figma.mixed on VECTOR nodes if vertices have different strokeCap values
|
||||||
|
strokeJoin: StrokeJoin | symbol // This can return figma.mixed on VECTOR nodes if vertices have different strokeJoin values
|
||||||
|
dashPattern: ReadonlyArray<number>
|
||||||
|
fillStyleId: string | symbol // This can return figma.mixed on TEXT nodes
|
||||||
|
strokeStyleId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CornerMixin {
|
||||||
|
// This can return figma.mixed on VECTOR nodes if vertices have different cornerRadius values,
|
||||||
|
// and on RECTANGLE nodes if node.topLeftRadius etc has different values
|
||||||
|
cornerRadius: number | symbol
|
||||||
|
|
||||||
|
cornerSmoothing: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExportMixin {
|
||||||
|
exportSettings: ExportSettings[]
|
||||||
|
exportAsync(settings?: ExportSettings): Promise<Uint8Array> // Defaults to PNG format
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Nodes
|
||||||
|
|
||||||
|
interface DocumentNode extends BaseNodeMixin, ChildrenMixin {
|
||||||
|
readonly type: "DOCUMENT"
|
||||||
|
clone(): DocumentNode // Note: this always throws an error
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PageNode extends BaseNodeMixin, ChildrenMixin, ExportMixin {
|
||||||
|
readonly type: "PAGE"
|
||||||
|
clone(): PageNode // cloned node starts off inserted into current page
|
||||||
|
|
||||||
|
guides: ReadonlyArray<Guide>
|
||||||
|
selection: ReadonlyArray<BaseNode>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FrameNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, FrameMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "FRAME" | "GROUP"
|
||||||
|
clone(): FrameNode // cloned node starts off inserted into current page
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SliceNode extends BaseNodeMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "SLICE"
|
||||||
|
clone(): SliceNode // cloned node starts off inserted into current page
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RectangleNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "RECTANGLE"
|
||||||
|
clone(): RectangleNode // cloned node starts off inserted into current page
|
||||||
|
topLeftRadius: number
|
||||||
|
topRightRadius: number
|
||||||
|
bottomLeftRadius: number
|
||||||
|
bottomRightRadius: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LineNode extends BaseNodeMixin, BlendMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "LINE"
|
||||||
|
clone(): LineNode // cloned node starts off inserted into current page
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EllipseNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "ELLIPSE"
|
||||||
|
clone(): EllipseNode // cloned node starts off inserted into current page
|
||||||
|
arcData: ArcData
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PolygonNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "POLYGON"
|
||||||
|
clone(): PolygonNode // cloned node starts off inserted into current page
|
||||||
|
pointCount: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StarNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "STAR"
|
||||||
|
clone(): StarNode // cloned node starts off inserted into current page
|
||||||
|
pointCount: number
|
||||||
|
|
||||||
|
// This is a percentage value from 0 to 1
|
||||||
|
innerRadius: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VectorNode extends BaseNodeMixin, BlendMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "VECTOR"
|
||||||
|
clone(): VectorNode // cloned node starts off inserted into current page
|
||||||
|
vectorNetwork: VectorNetwork
|
||||||
|
vectorPaths: VectorPaths
|
||||||
|
handleMirroring: HandleMirroring | symbol // This can return figma.mixed if vertices have different handleMirroring values
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TextNode extends BaseNodeMixin, BlendMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "TEXT"
|
||||||
|
clone(): TextNode // cloned node starts off inserted into current page
|
||||||
|
characters: string
|
||||||
|
textAlignHorizontal: "LEFT" | "CENTER" | "RIGHT" | "JUSTIFIED"
|
||||||
|
textAlignVertical: "TOP" | "CENTER" | "BOTTOM"
|
||||||
|
textAutoResize: "NONE" | "WIDTH_AND_HEIGHT" | "HEIGHT"
|
||||||
|
paragraphIndent: number
|
||||||
|
paragraphSpacing: number
|
||||||
|
autoRename: boolean
|
||||||
|
|
||||||
|
// These properties can all return figma.mixed if the text has multiple values for the property
|
||||||
|
textStyleId: string | symbol
|
||||||
|
fontSize: number | symbol
|
||||||
|
fontName: FontName | symbol
|
||||||
|
textCase: "ORIGINAL" | "UPPER" | "LOWER" | "TITLE" | symbol
|
||||||
|
textDecoration: "NONE" | "UNDERLINE" | "STRIKETHROUGH" | symbol
|
||||||
|
letterSpacing: NumberWithUnits | symbol
|
||||||
|
lineHeight: NumberWithUnits | symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ComponentNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, FrameMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "COMPONENT"
|
||||||
|
clone(): ComponentNode // cloned node starts off inserted into current page
|
||||||
|
|
||||||
|
createInstance(): InstanceNode // instance starts off inserted into current page
|
||||||
|
description: string
|
||||||
|
readonly remote: boolean
|
||||||
|
readonly key: string // The key to use with "importComponentByKeyAsync"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InstanceNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, FrameMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "INSTANCE"
|
||||||
|
clone(): InstanceNode // cloned node starts off inserted into current page
|
||||||
|
masterComponent: ComponentNode
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BooleanOperationNode extends BaseNodeMixin, BlendMixin, ChildrenMixin, CornerMixin, GeometryMixin, LayoutMixin, ExportMixin {
|
||||||
|
readonly type: "BOOLEAN_OPERATION"
|
||||||
|
clone(): BooleanOperationNode // cloned node starts off inserted into current page
|
||||||
|
booleanOperation: "UNION" | "INTERSECT" | "SUBTRACT" | "EXCLUDE"
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseNode =
|
||||||
|
DocumentNode |
|
||||||
|
PageNode |
|
||||||
|
SliceNode |
|
||||||
|
FrameNode |
|
||||||
|
ComponentNode |
|
||||||
|
InstanceNode |
|
||||||
|
BooleanOperationNode |
|
||||||
|
VectorNode |
|
||||||
|
StarNode |
|
||||||
|
LineNode |
|
||||||
|
EllipseNode |
|
||||||
|
PolygonNode |
|
||||||
|
RectangleNode |
|
||||||
|
TextNode
|
||||||
|
|
||||||
|
type NodeType =
|
||||||
|
"DOCUMENT" |
|
||||||
|
"PAGE" |
|
||||||
|
"SLICE" |
|
||||||
|
"FRAME" |
|
||||||
|
"GROUP" |
|
||||||
|
"COMPONENT" |
|
||||||
|
"INSTANCE" |
|
||||||
|
"BOOLEAN_OPERATION" |
|
||||||
|
"VECTOR" |
|
||||||
|
"STAR" |
|
||||||
|
"LINE" |
|
||||||
|
"ELLIPSE" |
|
||||||
|
"POLYGON" |
|
||||||
|
"RECTANGLE" |
|
||||||
|
"TEXT"
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Styles
|
||||||
|
type StyleType = "PAINT" | "TEXT" | "EFFECT" | "GRID"
|
||||||
|
|
||||||
|
interface BaseStyle {
|
||||||
|
// The string to uniquely identify a style by
|
||||||
|
readonly id: string
|
||||||
|
readonly type: StyleType
|
||||||
|
name: string // Note: setting this also sets "autoRename" to false on TextNodes
|
||||||
|
description: string
|
||||||
|
remote: boolean
|
||||||
|
readonly key: string // The key to use with "importStyleByKeyAsync"
|
||||||
|
remove(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PaintStyle extends BaseStyle {
|
||||||
|
type: "PAINT"
|
||||||
|
paints: ReadonlyArray<Paint>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TextStyle extends BaseStyle {
|
||||||
|
type: "TEXT"
|
||||||
|
fontSize: number
|
||||||
|
textDecoration: "NONE" | "UNDERLINE" | "STRIKETHROUGH"
|
||||||
|
fontName: FontName
|
||||||
|
letterSpacing: NumberWithUnits
|
||||||
|
lineHeight: NumberWithUnits
|
||||||
|
paragraphIndent: number
|
||||||
|
paragraphSpacing: number
|
||||||
|
textCase: "ORIGINAL" | "UPPER" | "LOWER" | "TITLE"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EffectStyle extends BaseStyle {
|
||||||
|
type: "EFFECT"
|
||||||
|
effects: ReadonlyArray<Paint>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GridStyle extends BaseStyle {
|
||||||
|
type: "GRID"
|
||||||
|
layoutGrids: ReadonlyArray<LayoutGrid>
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Other
|
||||||
|
|
||||||
|
interface Image {
|
||||||
|
// Returns a unique hash for the image
|
||||||
|
readonly hash: string
|
||||||
|
|
||||||
|
// The contents of the image file
|
||||||
|
getBytesAsync(): Promise<Uint8Array>
|
||||||
|
}
|
||||||
BIN
packages/lucide-figma/icon.png
Normal file
BIN
packages/lucide-figma/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
7
packages/lucide-figma/manifest.json
Normal file
7
packages/lucide-figma/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Lucide Icons",
|
||||||
|
"id": "939567362549682242",
|
||||||
|
"api": "1.0.0",
|
||||||
|
"ui": "build/ui.html",
|
||||||
|
"main": "build/main.js"
|
||||||
|
}
|
||||||
26
packages/lucide-figma/package.json
Normal file
26
packages/lucide-figma/package.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "lucide-figma",
|
||||||
|
"version": "0.13.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "build/ui.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --mode=production",
|
||||||
|
"watch": "webpack --mode=development --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/core": "^10.0.14",
|
||||||
|
"@types/react": "^16.8.23",
|
||||||
|
"@types/react-dom": "^16.8.4",
|
||||||
|
"css-loader": "^3.0.0",
|
||||||
|
"html-webpack-inline-source-plugin": "^0.0.10",
|
||||||
|
"html-webpack-plugin": "^3.2.0",
|
||||||
|
"lucide-react": "^0.13.0",
|
||||||
|
"react": "^16.8.6",
|
||||||
|
"react-dom": "^16.8.6",
|
||||||
|
"style-loader": "^0.23.1",
|
||||||
|
"ts-loader": "^6.0.4",
|
||||||
|
"typescript": "^3.5.2",
|
||||||
|
"webpack": "^4.35.2",
|
||||||
|
"webpack-cli": "^3.3.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
44
packages/lucide-figma/src/components/icon-button.tsx
Normal file
44
packages/lucide-figma/src/components/icon-button.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { jsx } from '@emotion/core'
|
||||||
|
import theme from '../theme'
|
||||||
|
import { renderToString } from 'react-dom/server'
|
||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
|
interface IconButtonProps {
|
||||||
|
name: string,
|
||||||
|
component: FC,
|
||||||
|
}
|
||||||
|
|
||||||
|
function IconButton({ name, component: IconComponent }: IconButtonProps) {
|
||||||
|
const onIconclick = () => {
|
||||||
|
const svg = renderToString(<IconComponent/>);
|
||||||
|
|
||||||
|
parent.postMessage({ pluginMessage: { name, svg }}, '*')
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={name}
|
||||||
|
aria-label={name}
|
||||||
|
onClick={onIconclick}
|
||||||
|
css={{
|
||||||
|
padding: theme.space[2],
|
||||||
|
color: '#333',
|
||||||
|
background: 'transparent',
|
||||||
|
border: 0,
|
||||||
|
borderRadius: theme.radii[1],
|
||||||
|
appearance: 'none',
|
||||||
|
outline: 0,
|
||||||
|
'&:hover': {
|
||||||
|
background: 'rgba(0, 0, 0, 0.06)',
|
||||||
|
},
|
||||||
|
'&:focus, &:active': {
|
||||||
|
boxShadow: `inset 0 0 0 2px ${theme.colors.blue}`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconComponent />
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconButton
|
||||||
24
packages/lucide-figma/src/components/search-icon.tsx
Normal file
24
packages/lucide-figma/src/components/search-icon.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { createElement, forwardRef } from 'react'
|
||||||
|
|
||||||
|
const SearchIcon = forwardRef((props: any, ref) => createElement(
|
||||||
|
'svg',
|
||||||
|
{
|
||||||
|
xmlns: "http://www.w3.org/2000/svg",
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
clipRule: 'evenodd',
|
||||||
|
fillRule: 'evenodd',
|
||||||
|
ref,
|
||||||
|
...props,
|
||||||
|
},
|
||||||
|
[
|
||||||
|
createElement(
|
||||||
|
'path', {
|
||||||
|
d: 'm20 15c0 2.7614-2.2386 5-5 5s-5-2.2386-5-5 2.2386-5 5-5 5 2.2386 5 5zm-1.1256 4.5815c-1.0453.8849-2.3975 1.4185-3.8744 1.4185-3.3137 0-6-2.6863-6-6s2.6863-6 6-6 6 2.6863 6 6c0 1.4769-.5336 2.8291-1.4185 3.8744l4.2721 4.272-.7072.7072z',
|
||||||
|
key: 'path'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
))
|
||||||
|
|
||||||
|
export default SearchIcon
|
||||||
43
packages/lucide-figma/src/components/search-input.tsx
Normal file
43
packages/lucide-figma/src/components/search-input.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { jsx } from '@emotion/core'
|
||||||
|
import theme from '../theme'
|
||||||
|
import SearchIcon from './search-icon'
|
||||||
|
interface SearchInputProps extends React.HTMLProps<HTMLDivElement> {
|
||||||
|
value: string,
|
||||||
|
iconCount: number,
|
||||||
|
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
function SearchInput({ value, onChange, iconCount, ...props }: SearchInputProps) {
|
||||||
|
return (
|
||||||
|
<div css={{ position: 'relative' }} {...props}>
|
||||||
|
<div
|
||||||
|
css={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
padding: theme.space[1],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SearchIcon fill="#333" />
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
autoFocus
|
||||||
|
type="search"
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
placeholder={`Search ${iconCount} icons`}
|
||||||
|
css={{
|
||||||
|
width: '100%',
|
||||||
|
height: 40,
|
||||||
|
padding: `0 ${theme.space[4]} 0 36px`,
|
||||||
|
fontFamily: 'inherit',
|
||||||
|
fontSize: theme.fontSizes[0],
|
||||||
|
border: 0,
|
||||||
|
outline: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchInput
|
||||||
21
packages/lucide-figma/src/helpers/naming.ts
Normal file
21
packages/lucide-figma/src/helpers/naming.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Converts string to camelcase
|
||||||
|
*
|
||||||
|
* @param {string} string
|
||||||
|
*/
|
||||||
|
export const toCamelCase = (string: string) =>
|
||||||
|
string.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) =>
|
||||||
|
p2 ? p2.toUpperCase() : p1.toLowerCase(),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts string to PascalCase
|
||||||
|
*
|
||||||
|
* @param {string} string
|
||||||
|
*/
|
||||||
|
export const toPascalCase = (string: string) => {
|
||||||
|
const camelCase = toCamelCase(string);
|
||||||
|
|
||||||
|
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
||||||
|
};
|
||||||
9
packages/lucide-figma/src/main.ts
Normal file
9
packages/lucide-figma/src/main.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
figma.showUI(__html__, { width: 300, height: 400 })
|
||||||
|
|
||||||
|
figma.ui.onmessage = ({name, svg}) => {
|
||||||
|
const icon = figma.createNodeFromSvg(svg)
|
||||||
|
icon.name = name
|
||||||
|
icon.x = figma.viewport.center.x
|
||||||
|
icon.y = figma.viewport.center.y
|
||||||
|
figma.currentPage.selection = [icon]
|
||||||
|
}
|
||||||
8
packages/lucide-figma/src/theme.ts
Normal file
8
packages/lucide-figma/src/theme.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
space: [0, 4, 8, 12, 16],
|
||||||
|
fontSizes: [12, 14, 16],
|
||||||
|
colors: {
|
||||||
|
blue: '#18a0fb',
|
||||||
|
},
|
||||||
|
radii: [0, 2],
|
||||||
|
}
|
||||||
4
packages/lucide-figma/src/types/lucide-react.ts
Normal file
4
packages/lucide-figma/src/types/lucide-react.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
declare module 'lucide-react';
|
||||||
|
declare module 'lucide';
|
||||||
|
declare module 'lucide/icons';
|
||||||
|
declare module 'lucide/build/icons';
|
||||||
10
packages/lucide-figma/src/ui.css
Normal file
10
packages/lucide-figma/src/ui.css
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: 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')
|
||||||
|
format('woff');
|
||||||
|
}
|
||||||
1
packages/lucide-figma/src/ui.html
Normal file
1
packages/lucide-figma/src/ui.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<div id="root"></div>
|
||||||
82
packages/lucide-figma/src/ui.tsx
Normal file
82
packages/lucide-figma/src/ui.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { Global, jsx } from '@emotion/core'
|
||||||
|
import { version } from '../package.json'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import IconButton from './components/icon-button'
|
||||||
|
import SearchInput from './components/search-input'
|
||||||
|
import theme from './theme'
|
||||||
|
import './ui.css'
|
||||||
|
import tags from '../../../tags.json'
|
||||||
|
import * as iconComponents from 'lucide-react'
|
||||||
|
import { toPascalCase } from './helpers/naming';
|
||||||
|
import useSearch from '../../../site/src/lib/useSearch';
|
||||||
|
|
||||||
|
declare var ICONS: [];
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const [query, setQuery] = React.useState('')
|
||||||
|
const icons = ICONS.map(name => {
|
||||||
|
const componentName = toPascalCase(name);
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
tags: tags[name] || [],
|
||||||
|
component: iconComponents[componentName] || null
|
||||||
|
}
|
||||||
|
}).filter(({component}) => !!component)
|
||||||
|
|
||||||
|
const searchResults = useMemo(() => useSearch(icons, query), [icons, query])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Global
|
||||||
|
styles={{ body: { margin: 0, fontFamily: 'Inter, sans-serif' } }}
|
||||||
|
/>
|
||||||
|
<SearchInput
|
||||||
|
value={query}
|
||||||
|
iconCount={icons.length}
|
||||||
|
onChange={event => setQuery(event.target.value)}
|
||||||
|
css={{
|
||||||
|
position: 'sticky',
|
||||||
|
top: 0,
|
||||||
|
borderBottom: '1px solid #e5e5e5',
|
||||||
|
backfaceVisibility: 'hidden'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div css={{ padding: theme.space[2] }}>
|
||||||
|
<div
|
||||||
|
css={{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: 'repeat(6, 1fr)',
|
||||||
|
gridGap: theme.space[1],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{searchResults.map(({name, component: Icon} :any) => (
|
||||||
|
<IconButton
|
||||||
|
name={name}
|
||||||
|
key={name}
|
||||||
|
component={Icon}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
css={{
|
||||||
|
marginTop: theme.space[2],
|
||||||
|
padding: theme.space[2],
|
||||||
|
fontSize: theme.fontSizes[0],
|
||||||
|
color: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://lucide.dev"
|
||||||
|
target="_blank"
|
||||||
|
css={{ color: 'inherit' }}
|
||||||
|
>
|
||||||
|
Lucide v{version}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactDOM.render(<App />, document.getElementById('root'))
|
||||||
12
packages/lucide-figma/tsconfig.json
Normal file
12
packages/lucide-figma/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"lib": ["dom", "esnext"],
|
||||||
|
"jsx": "react",
|
||||||
|
"jsxFactory": "jsx",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"strict": true,
|
||||||
|
"allowJs": true,
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules"],
|
||||||
|
}
|
||||||
48
packages/lucide-figma/webpack.config.js
Normal file
48
packages/lucide-figma/webpack.config.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
module.exports = (env, argv) => ({
|
||||||
|
// This is necessary because Figma's 'eval' works differently than normal eval
|
||||||
|
devtool: argv.mode === 'production' ? false : 'inline-source-map',
|
||||||
|
entry: {
|
||||||
|
ui: './src/ui.tsx',
|
||||||
|
main: './src/main.ts',
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
path: path.resolve(__dirname, 'build'),
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: 'ts-loader',
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
loader: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.tsx', '.ts', '.js'],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
ICONS: JSON.stringify(
|
||||||
|
fs.readdirSync(path.join(process.cwd(), '../../icons')).map(name => name.split('.')[0]),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './src/ui.html',
|
||||||
|
filename: 'ui.html',
|
||||||
|
inlineSource: '.(js)$',
|
||||||
|
chunks: ['ui'],
|
||||||
|
}),
|
||||||
|
new HtmlWebpackInlineSourcePlugin(),
|
||||||
|
],
|
||||||
|
});
|
||||||
3599
packages/lucide-figma/yarn.lock
Normal file
3599
packages/lucide-figma/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "lucide-react",
|
"name": "lucide-react",
|
||||||
"description": "Lucide React package, Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
|
"description": "Lucide React package, Lucide is a community-run fork of Feather Icons, open for anyone to contribute icons.",
|
||||||
"version": "0.13.0",
|
"version": "0.14.1",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"homepage": "https://lucide.dev",
|
"homepage": "https://lucide.dev",
|
||||||
"bugs": "https://github.com/lucide-icons/lucide/issues",
|
"bugs": "https://github.com/lucide-icons/lucide/issues",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default (iconName, [tag, attrs, children]) => {
|
|||||||
Component.propTypes = {
|
Component.propTypes = {
|
||||||
color: PropTypes.string,
|
color: PropTypes.string,
|
||||||
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
strokeWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
};
|
};
|
||||||
|
|
||||||
Component.displayName = `${iconName}`;
|
Component.displayName = `${iconName}`;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lucide-vue",
|
"name": "lucide-vue",
|
||||||
"version": "0.13.0-beta.1",
|
"version": "0.14.0",
|
||||||
"author": "Eric Fennis",
|
"author": "Eric Fennis",
|
||||||
"description": "Lucide Vue Package",
|
"description": "Lucide Vue Package",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|||||||
@@ -22,6 +22,13 @@ export const toPascalCase = string => {
|
|||||||
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts string to PascalCase
|
||||||
|
*
|
||||||
|
* @param {string} string
|
||||||
|
*/
|
||||||
|
export const toKebabCase = string => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the file contents.
|
* Resets the file contents.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
interface Icon {
|
||||||
import { useDebounce } from './useDebounce';
|
name: string;
|
||||||
|
tags: string[],
|
||||||
|
}
|
||||||
|
|
||||||
function useSearch(icons: Array<any>, query:string) {
|
function useSearch(icons: Icon[], query:string) {
|
||||||
if(!query) return icons;
|
if(!query) return icons;
|
||||||
|
|
||||||
const searchString = query.toLowerCase()
|
const searchString = query.toLowerCase()
|
||||||
|
|
||||||
return icons.filter(({ name, tags }) => {
|
return icons.filter(({ name, tags }: Icon) => [name, ...tags].some(
|
||||||
const icon = { name, tags };
|
(item:string) => item
|
||||||
|
.toLowerCase()
|
||||||
return Object.keys(icon).some(
|
.includes(searchString)
|
||||||
key => String(icon[key])
|
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchString)
|
|
||||||
)
|
)
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useSearch;
|
export default useSearch;
|
||||||
|
|||||||
Reference in New Issue
Block a user