Skip to content

Commit cfdf17e

Browse files
author
Rob Cresswell
committed
feat: Upgrade MDI & match vue styleguide
BREAKING CHANGE: Match the component names to the structure recommended by the Vue style guide. This means all files now begin with a capital letter, i.e. "android.vue" is now "Android.vue", and the component names are Pascal-cased instead of camel-cased. i.e. "CheckboxMarkedCircle" instead of "checkbox-marked-circle". Other changes include: - Async build script, to make it a little faster. Also refactored to use the new @mdi/svg repo, so some of the build hacks can go away. - Added some testing and snapshots, to make upgrades quicker to verify. - Updated to the lastest version of MDI for more icons. - Updated the LICENSE for 2018 - Added .nvmrc - Fairly unimportant, but the generated .vue files now pass all the rules on the Vue style guide; this should make them a little more consistent and easier to read for those familiar with Vue. Fixes #1, #2
1 parent 8315c97 commit cfdf17e

File tree

12 files changed

+6844
-937
lines changed

12 files changed

+6844
-937
lines changed

.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": [["@babel/preset-env", {"targets": { "node": "current" }}]]
3+
}

.gitmodules

Whitespace-only changes.

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
10.8

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2017 Rob Cresswell
3+
Copyright (c) 2018 Rob Cresswell
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ easier.
3131
3. Import the icon, and declare it as a local component:
3232

3333
```javascript
34-
import MenuIcon from "vue-material-design-icons/menu.vue"
34+
import MenuIcon from "vue-material-design-icons/Menu.vue"
3535

3636
components: {
3737
MenuIcon
@@ -43,13 +43,13 @@ easier.
4343
Declare it as a global component:
4444

4545
```javascript
46-
import MenuIcon from "vue-material-design-icons/menu.vue"
46+
import MenuIcon from "vue-material-design-icons/Menu.vue"
4747

4848
Vue.component("menu-icon", MenuIcon)
4949
```
5050

51-
> **Note** Icon files are kebab cased, e.g. `checkbox-marked-circle.vue`, and
52-
> their default name has `-icon` appended e.g. `checkbox-marked-circle-icon`.
51+
> **Note** Icon files are pascal cased, e.g. `CheckboxMarkedCircle.vue`, and
52+
> their default name has `Icon` appended e.g. `CheckboxMarkedCircleIcon`.
5353

5454
4. Then use it in your template code!
5555

@@ -94,10 +94,11 @@ easier.
9494

9595
A list of the icons can be found at the
9696
[Material Design Icons website](https://materialdesignicons.com/
97-
"Material Design Icons website"). The icons packaged here match the names
98-
displayed on the website, such as `ultra-high-definition`, with the `.vue`
99-
extension; that icon would be imported as
100-
`"vue-material-design-icons/ultra-high-definition.vue"`.
97+
"Material Design Icons website"). The icons packaged here are pascal cased
98+
versions of the names displayed on the website, to match the
99+
[Vue Style Guide](https://vuejs.org/v2/style-guide/). For example, the icon
100+
named `ultra-high-definition` would be imported as
101+
`"vue-material-design-icons/UltraHighDefinition.vue"`.
101102

102103
## Tips
103104

@@ -115,8 +116,8 @@ extension; that icon would be imported as
115116
```
116117

117118
This will give you much shorter and more readable imports, like
118-
`import Android from "icons/android"`, rather than
119-
`import Android from "vue-material-design-icons/android.vue"`. Much better!
119+
`import Android from "icons/Android"`, rather than
120+
`import Android from "vue-material-design-icons/Android.vue"`. Much better!
120121

121122
- Add click handlers to the icons with `@click.native`. For example:
122123

__tests__/__snapshots__/icon.js.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Icon renders an icon 1`] = `<span aria-label="Android icon" role="img" class="material-design-icon android-icon"><svg fill="currentColor" width="24" height="24" viewBox="0 0 24 24" class="material-design-icon__svg"><title>Android icon</title> <path d="M15,5H14V4H15M10,5H9V4H10M15.53,2.16L16.84,0.85C17.03,0.66 17.03,0.34 16.84,0.14C16.64,-0.05 16.32,-0.05 16.13,0.14L14.65,1.62C13.85,1.23 12.95,1 12,1C11.04,1 10.14,1.23 9.34,1.63L7.85,0.14C7.66,-0.05 7.34,-0.05 7.15,0.14C6.95,0.34 6.95,0.66 7.15,0.85L8.46,2.16C6.97,3.26 6,5 6,7H18C18,5 17,3.25 15.53,2.16M20.5,8C19.67,8 19,8.67 19,9.5V16.5C19,17.33 19.67,18 20.5,18C21.33,18 22,17.33 22,16.5V9.5C22,8.67 21.33,8 20.5,8M3.5,8C2.67,8 2,8.67 2,9.5V16.5C2,17.33 2.67,18 3.5,18C4.33,18 5,17.33 5,16.5V9.5C5,8.67 4.33,8 3.5,8M6,18C6,18.55 6.45,19 7,19H8V22.5C8,23.33 8.67,24 9.5,24C10.33,24 11,23.33 11,22.5V19H13V22.5C13,23.33 13.67,24 14.5,24C15.33,24 16,23.33 16,22.5V19H17C17.55,19 18,18.55 18,18V8H6V18Z"></path></svg></span>`;

__tests__/icon.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { shallowMount } from "@vue/test-utils";
2+
import AndroidIcon from "../dist/Android.vue";
3+
4+
describe("Icon", () => {
5+
let icon;
6+
7+
beforeEach(() => {
8+
icon = shallowMount(AndroidIcon);
9+
});
10+
11+
it("accepts a \"title\" property", () => {
12+
expect(icon.vm.title).toEqual("Android icon");
13+
expect(icon.attributes()["aria-label"]).toEqual("Android icon");
14+
15+
icon.setProps({ title: "foo" });
16+
17+
expect(icon.vm.title).toEqual("foo");
18+
expect(icon.attributes()["aria-label"]).toEqual("foo");
19+
});
20+
21+
it("accepts a \"decorative\" property", () => {
22+
expect(icon.vm.decorative).toBe(false);
23+
expect(icon.attributes()["aria-hidden"]).toBeFalsy();
24+
25+
icon.setProps({ decorative: true });
26+
27+
expect(icon.vm.decorative).toBe(true);
28+
expect(icon.attributes()["aria-hidden"]).toBeTruthy();
29+
});
30+
31+
it("accepts a \"fillColor\" property", () => {
32+
const svg = icon.find(".material-design-icon__svg");
33+
34+
expect(icon.vm.fillColor).toBe("currentColor");
35+
expect(svg.attributes()["fill"]).toEqual("currentColor");
36+
37+
icon.setProps({ fillColor: "#FF0000" });
38+
39+
expect(icon.vm.fillColor).toBe("#FF0000");
40+
expect(svg.attributes()["fill"]).toEqual("#FF0000");
41+
});
42+
43+
it("renders an icon", () => {
44+
expect(icon).toMatchSnapshot();
45+
});
46+
});

build.js

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,57 @@
11
#!/usr/bin/env node
22

3+
// Imports
34
const fs = require("fs");
5+
const fsp = require("fs").promises;
46
const mustache = require("mustache");
57
const path = require("path");
6-
8+
const icons = require("@mdi/js/commonjs/mdi.js");
79
const dist = path.resolve(__dirname, "dist");
8-
const template = path.resolve(__dirname, "template.mst");
9-
const svgPath = path.resolve(__dirname, "node_modules/@mdi/svg/svg");
10+
const templateFile = path.resolve(__dirname, "template.mst");
11+
const iconIDs = Object.keys(icons);
1012

11-
const svgs = fs.readdirSync(svgPath);
13+
const templateData = iconIDs.map(id => {
14+
const splitID = id.split(/(?=[A-Z])/).slice(1);
1215

13-
const getPath = svg => {
14-
const matches = /\sd="(.*)"/.exec(
15-
fs.readFileSync(path.join(svgPath, svg), {
16-
encoding: "utf8"
17-
})
18-
);
16+
const name = splitID.join("");
1917

20-
if (matches) {
21-
return matches[0];
22-
}
23-
};
18+
// This is a hacky way to remove the 'mdi' prefix, so "mdiAndroid" becomes
19+
// "android", for example
20+
const title = splitID.join("-").toLowerCase();
2421

25-
const makeHumanReadable = name => {
26-
const spacedName = name.split("-").join(" ");
27-
humanReadableName = spacedName.charAt(0).toUpperCase() + spacedName.slice(1);
28-
return humanReadableName;
29-
};
22+
// Transforms the icon ID to a human readable form for default titles.
23+
// For example, "mdiAndroidStudio" becomes "Android Studio"
24+
const readableName = splitID.join(" ");
3025

31-
const templateData = svgs.map(svg => {
32-
const name = svg.slice(0, -4);
3326
return {
34-
name: name,
35-
readableName: makeHumanReadable(name),
36-
path: getPath(svg)
27+
name,
28+
title,
29+
readableName,
30+
svgPathData: icons[id]
3731
};
3832
});
3933

40-
const componentFile = fs.readFileSync(template, { encoding: "utf8" });
34+
const generateIcons = async () => {
35+
const template = fs.readFileSync(templateFile, { encoding: "utf8" });
4136

42-
if (!fs.existsSync(dist)) {
43-
fs.mkdirSync(dist);
44-
}
37+
if (!fs.existsSync(dist)) {
38+
fs.mkdirSync(dist);
39+
}
40+
41+
const filePromises = templateData.map(
42+
({ name, title, readableName, svgPathData }) => {
43+
const component = mustache.render(template, {
44+
name,
45+
title,
46+
readableName,
47+
svgPathData
48+
});
49+
const filename = `${name}.vue`;
50+
return fsp.writeFile(path.resolve(dist, filename), component);
51+
}
52+
);
53+
54+
Promise.all(filePromises);
55+
};
4556

46-
for (data of templateData) {
47-
const component = mustache.render(componentFile, data);
48-
const filename = data.name + ".vue";
49-
fs.writeFileSync(path.resolve(dist, filename), component);
50-
}
57+
generateIcons();

jest.config.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module.exports = {
2+
"verbose": true,
3+
"moduleFileExtensions": [
4+
"js",
5+
"vue"
6+
],
7+
"transform": {
8+
"^.+\\.vue$": "vue-jest",
9+
"^.+\\.js$": "<rootDir>/node_modules/babel-jest"
10+
},
11+
"snapshotSerializers": [
12+
"<rootDir>/node_modules/jest-serializer-vue"
13+
]
14+
};

0 commit comments

Comments
 (0)