Skip to content

Commit ba5286a

Browse files
committed
fix(icon): improve autofix path
1 parent f32bc4d commit ba5286a

File tree

873 files changed

+1607
-1739
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

873 files changed

+1607
-1739
lines changed

packages/persona-icon/font/persona-icon.css

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
@font-face {
22
font-family: 'Persona Icon';
3-
src: url('../font/persona-icon.eot?6587e0b3');
4-
src: url('../font/persona-icon.eot?6587e0b3#iefix') format('embedded-opentype'),
5-
url('../font/persona-icon.woff2?257ac2c8') format('woff2'),
6-
url('../font/persona-icon.woff?fa851bfd') format('woff'),
7-
url('../font/persona-icon.ttf?c403a530') format('truetype'),
8-
url('../font/persona-icon.svg?38d4d315#Persona%20Icon') format('svg');
3+
src: url('../font/persona-icon.eot?167536ca');
4+
src: url('../font/persona-icon.eot?167536ca#iefix') format('embedded-opentype'),
5+
url('../font/persona-icon.woff2?033d4851') format('woff2'),
6+
url('../font/persona-icon.woff?fc0bcfd8') format('woff'),
7+
url('../font/persona-icon.ttf?71a4b6fd') format('truetype'),
8+
url('../font/persona-icon.svg?4d4454fa#Persona%20Icon') format('svg');
99
font-weight: normal;
1010
font-style: normal;
1111
}
-384 Bytes
Binary file not shown.

packages/persona-icon/font/persona-icon.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@
9595
""
9696
],
9797
"width": 1000,
98-
"height": 1000,
99-
"color": "url(#b)"
98+
"height": 1000
10099
},
101100
{
102101
"name": "admin-center-logo-apps",

packages/persona-icon/font/persona-icon.svg

Lines changed: 110 additions & 110 deletions
Loading
-384 Bytes
Binary file not shown.
316 Bytes
Binary file not shown.
224 Bytes
Binary file not shown.

packages/persona-icon/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
"scripts": {
4141
"prepack": "yarn build",
4242
"build": "nuxt-module-build build",
43-
"lint": "jiti scripts/lint.ts",
44-
"sync": "jiti scripts/sync.ts",
45-
"changelog": "jiti scripts/changelog.ts"
43+
"lint": "node --import jiti/register scripts/lint.ts",
44+
"sync": "node --import jiti/register scripts/sync.ts",
45+
"changelog": "node --import jiti/register scripts/changelog.ts"
4646
},
4747
"devDependencies": {
4848
"@nuxt/module-builder": "1.0.1",

packages/persona-icon/scripts/fix-svg.ts

Lines changed: 130 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,32 @@ type Point = ReturnType<typeof SVGPath['getPointAtLength']>
77
export function fixPath (d: string): string {
88
const path = SVGPath.normalizePath(d)
99
const paths = sortPaths(SVGPath.splitPath(path))
10+
const root = new PathTree()
1011

11-
for (const [i, cur] of paths.entries()) {
12-
if (i > 0) {
13-
const outer = paths[0]
14-
const prev = paths[i - 1]
12+
for (const p of paths)
13+
root.addChild(new PathTree(p))
1514

16-
const needRotate = (isInside(cur, prev) && isClockwise(cur) === isClockwise(prev))
17-
|| (isInside(cur, outer) && isClockwise(cur) === isClockwise(outer))
15+
const nodes = [...root.children]
16+
const result: PathArray[] = []
1817

19-
if (needRotate)
20-
paths[i] = SVGPath.reversePath(cur)
21-
}
22-
}
18+
while (nodes.length > 0) {
19+
const node = nodes.shift()
2320

24-
return SVGPath.pathToString(paths.flat() as PathArray)
25-
}
21+
if (!node)
22+
break
2623

27-
function isInside (inner: PathArray, outer: PathArray) {
28-
return isInBox(inner, outer)
29-
&& isInPolygon(inner, outer)
30-
}
24+
if (node.value) {
25+
if (node.parent && node.parent.dir === node.dir)
26+
node.reverse()
3127

32-
function isInBox (inner: PathArray, outer: PathArray) {
33-
const outerBox = SVGPath.getPathBBox(outer)
34-
const innerBox = SVGPath.getPathBBox(inner)
28+
result.push(node.value)
29+
}
30+
31+
if (node.children.size > 0)
32+
nodes.push(...node.children)
33+
}
3534

36-
return innerBox.x >= outerBox.x
37-
&& innerBox.y >= outerBox.y
38-
&& (innerBox.x + innerBox.width) <= (outerBox.x + outerBox.width)
39-
&& (innerBox.y + innerBox.height) <= (outerBox.y + outerBox.height)
35+
return SVGPath.pathToString(result.flat(1) as PathArray)
4036
}
4137

4238
function isInPolygon (inner: PathArray, outer: PathArray) {
@@ -63,13 +59,25 @@ function getPolygon (path: PathArray, precission = 30) {
6359
const length = SVGPath.getTotalLength(path)
6460

6561
for (let i = 1; i <= precission; i++)
66-
points.push(SVGPath.getPointAtLength(path, length * (i / precission)))
62+
points.push(SVGPath.getPointAtLength(path, Math.round(length * (i / precission))))
6763

6864
return points
6965
}
7066

7167
function isClockwise (path: PathArray) {
72-
return SVGPath.getDrawDirection(path)
68+
const points = getPolygon(path)
69+
const n = points.length
70+
71+
let area = 0
72+
73+
for (let i = 0; i < n; i++) {
74+
const p1 = points[i]
75+
const p2 = points[(i + 1) % n]
76+
77+
area += (p1.x * p2.y - p2.x * p1.y)
78+
}
79+
80+
return (area / 2) < 0
7381
}
7482

7583
function sortPaths (paths: PathArray[]): PathArray[] {
@@ -90,3 +98,100 @@ function sortPaths (paths: PathArray[]): PathArray[] {
9098
return paths[box.index]
9199
})
92100
}
101+
102+
interface PathTreeJSON {
103+
value?: string,
104+
dir?: 'cw' | 'ccw',
105+
area?: number,
106+
children: PathTreeJSON[],
107+
}
108+
109+
export class PathTree {
110+
parent?: PathTree
111+
value?: PathArray
112+
children: Set<PathTree>
113+
114+
constructor (path?: PathArray) {
115+
this.value = path
116+
this.children = new Set()
117+
}
118+
119+
addChild (cur: PathTree) {
120+
if (this.value && this.compare(cur) === -1) {
121+
this.setParent(cur)
122+
123+
return this
124+
}
125+
126+
for (const child of this.children) {
127+
const c = child.compare(cur)
128+
129+
if (c === -1) {
130+
child.setParent(child)
131+
132+
return this
133+
}
134+
135+
if (c === 1) {
136+
child.addChild(cur)
137+
138+
return this
139+
}
140+
}
141+
142+
this.children.add(cur)
143+
144+
cur.parent = this
145+
146+
return this
147+
}
148+
149+
setParent (parent: PathTree) {
150+
if (this.parent)
151+
this.parent.children.delete(this)
152+
153+
parent.addChild(this)
154+
155+
this.parent = parent
156+
157+
return this
158+
}
159+
160+
get area () {
161+
if (this.value)
162+
return SVGPath.getPathArea(this.value)
163+
}
164+
165+
get dir () {
166+
if (this.value)
167+
return isClockwise(this.value) ? 'cw' : 'ccw'
168+
}
169+
170+
compare (other: PathTree) {
171+
if (this.value && other.value) {
172+
if (isInPolygon(other.value, this.value))
173+
return 1
174+
175+
if (isInPolygon(this.value, other.value))
176+
return -1
177+
}
178+
179+
return 0
180+
}
181+
182+
reverse () {
183+
if (this.value)
184+
this.value = SVGPath.reversePath(this.value)
185+
186+
return this
187+
}
188+
189+
toJSON (): PathTreeJSON {
190+
return {
191+
value : this.value ? SVGPath.pathToString(this.value) : undefined,
192+
dir : this.dir,
193+
area : this.area,
194+
children: Array.from(this.children, (c) => c.toJSON()),
195+
}
196+
}
197+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { fixPath } from './fix-svg.js'
2+
import { hash } from 'ohash'
3+
4+
export default {
5+
plugins: [
6+
{
7+
name: 'remove-clip-path',
8+
fn : () => {
9+
return {
10+
element: {
11+
exit (node, parentNode) {
12+
if (node.name === 'g' && node.attributes['clip-path']) {
13+
parentNode.children = node.children.map((child) => {
14+
if (child.type === 'element')
15+
node.attributes.fill = 'currentColor'
16+
17+
return child
18+
})
19+
}
20+
},
21+
},
22+
}
23+
},
24+
},
25+
{
26+
name: 'fix-path',
27+
fn : () => {
28+
return {
29+
element: {
30+
enter (node) {
31+
if (node.name === 'path') {
32+
if (node.attributes.d)
33+
node.attributes.d = fixPath(node.attributes.d)
34+
35+
if (node.attributes.fill && node.attributes.fill !== 'none' && !node.attributes.fill.startsWith('url'))
36+
node.attributes.fill = 'currentColor'
37+
}
38+
},
39+
},
40+
}
41+
},
42+
},
43+
{
44+
name : 'addClassesToSVGElement',
45+
params: { className: 'persona-icon' },
46+
},
47+
{
48+
name : 'addAttributesToSVGElement',
49+
params: { attributes: [{ focusable: 'false' }] },
50+
},
51+
{
52+
name : 'preset-default',
53+
params: { overrides: { removeViewBox: false } },
54+
},
55+
{
56+
name : 'prefixIds',
57+
params: {
58+
delim : '_',
59+
prefix : (_, info) => info.path ? hash(info.path) : '',
60+
prefixClassNames: false,
61+
prefixIds : true,
62+
},
63+
},
64+
],
65+
}

0 commit comments

Comments
 (0)