diff --git a/.github/ISSUE_TEMPLATE/icon-request.md b/.github/ISSUE_TEMPLATE/icon-request.md
index 0d161208e..acb1af491 100644
--- a/.github/ISSUE_TEMPLATE/icon-request.md
+++ b/.github/ISSUE_TEMPLATE/icon-request.md
@@ -2,7 +2,7 @@
name: Icon request
about: Requesting a new icon or changes to an existing icon
title: 'Icon request: [NAME]'
-labels: 'request: icon'
+labels: 'request:icon'
assignees: ''
---
diff --git a/.github/scripts/build_assets/SeleniumRunner.py b/.github/scripts/build_assets/SeleniumRunner.py
index da5091aea..b95d4a7c9 100644
--- a/.github/scripts/build_assets/SeleniumRunner.py
+++ b/.github/scripts/build_assets/SeleniumRunner.py
@@ -89,20 +89,11 @@ def upload_icomoon(self, icomoon_json_path: str):
:raises TimeoutException: happens when elements are not found.
"""
print("Uploading icomoon.json file...")
- try:
- self.click_hamburger_input()
-
- # find the file input and enter the file path
- import_btn = self.driver.find_element(By.XPATH, "(//li[@class='file'])[1]//input")
- import_btn.send_keys(icomoon_json_path)
- except SeleniumTimeoutException as e:
- print(e.stacktrace)
- print("Selenium timed out. Couldn't find import button.")
- self.close()
- raise e
- except Exception as e:
- self.close()
- raise e
+ self.click_hamburger_input()
+
+ # find the file input and enter the file path
+ import_btn = self.driver.find_element(By.XPATH, "(//li[@class='file'])[1]//input")
+ import_btn.send_keys(icomoon_json_path)
try:
confirm_btn = WebDriverWait(self.driver, SeleniumRunner.MED_WAIT_IN_SEC).until(
@@ -110,49 +101,42 @@ def upload_icomoon(self, icomoon_json_path: str):
)
confirm_btn.click()
except SeleniumTimeoutException as e:
- print(e.stacktrace)
- print("Cannot find the confirm button when uploading the icomoon.json",
- "Ensure that the icomoon.json is in the correct format for Icomoon.io",
- sep='\n')
- self.close()
+ raise Exception("Cannot find the confirm button when uploading the icomoon.json" \
+ "Ensure that the icomoon.json is in the correct format for Icomoon.io")
print("JSON file uploaded.")
- def upload_svgs(self, svgs: List[str]):
+ def upload_svgs(self, svgs: List[str], screenshot_folder: str=""):
"""
Upload the SVGs provided in folder_info
:param svgs: a list of svg Paths that we'll upload to icomoon.
+ :param screenshot_folder: the name of the screenshot_folder. If
+ the value is provided, it means the user want to take a screenshot
+ of each icon.
"""
- try:
- print("Uploading SVGs...")
+ print("Uploading SVGs...")
- edit_mode_btn = self.driver.find_element_by_css_selector(
- "div.btnBar button i.icon-edit"
- )
- edit_mode_btn.click()
-
- self.click_hamburger_input()
-
- for svg in svgs:
- import_btn = self.driver.find_element_by_css_selector(
- "li.file input[type=file]"
- )
- import_btn.send_keys(svg)
- print(f"Uploaded {svg}")
- self.test_for_possible_alert(self.SHORT_WAIT_IN_SEC, "Dismiss")
- self.remove_color_from_icon()
-
- # take a screenshot of the icons that were just added
- self.driver.save_screenshot("new_icons.png");
- self.click_hamburger_input()
- select_all_button = WebDriverWait(self.driver, self.LONG_WAIT_IN_SEC).until(
- ec.element_to_be_clickable((By.XPATH, "//button[text()='Select All']"))
+ edit_mode_btn = self.driver.find_element_by_css_selector(
+ "div.btnBar button i.icon-edit"
+ )
+ edit_mode_btn.click()
+
+ self.click_hamburger_input()
+
+ for i in range(len(svgs)):
+ import_btn = self.driver.find_element_by_css_selector(
+ "li.file input[type=file]"
)
- select_all_button.click()
- print("Finished uploading the svgs...")
- except Exception as e:
- self.close()
- raise e
+ import_btn.send_keys(svgs[i])
+ print(f"Uploaded {svgs[i]}")
+ self.test_for_possible_alert(self.SHORT_WAIT_IN_SEC, "Dismiss")
+ self.click_on_just_added_icon(screenshot_folder, i)
+
+ # take a screenshot of the icons that were just added
+ new_icons_path = str(Path(screenshot_folder, "new_icons.png").resolve())
+ self.driver.save_screenshot(new_icons_path);
+
+ print("Finished uploading the svgs...")
def click_hamburger_input(self):
"""
@@ -161,20 +145,16 @@ def click_hamburger_input(self):
input two times before the menu appears.
:return: None.
"""
- try:
- hamburger_input = self.driver.find_element_by_xpath(
- "(//i[@class='icon-menu'])[2]"
- )
+ hamburger_input = self.driver.find_element_by_xpath(
+ "(//i[@class='icon-menu'])[2]"
+ )
- menu_appear_callback = ec.element_to_be_clickable(
- (By.CSS_SELECTOR, "h1 ul.menuList2")
- )
+ menu_appear_callback = ec.element_to_be_clickable(
+ (By.CSS_SELECTOR, "h1 ul.menuList2")
+ )
- while not menu_appear_callback(self.driver):
- hamburger_input.click()
- except Exception as e:
- self.close()
- raise e
+ while not menu_appear_callback(self.driver):
+ hamburger_input.click()
def test_for_possible_alert(self, wait_period: float, btn_text: str):
"""
@@ -191,22 +171,37 @@ def test_for_possible_alert(self, wait_period: float, btn_text: str):
)
dismiss_btn.click()
except SeleniumTimeoutException:
- pass
+ pass # nothing found => everything is good
+
+ def click_on_just_added_icon(self, screenshot_folder: str, index: int):
+ """
+ Click on the most recently added icon so we can remove the colors
+ and take a snapshot if needed.
+ """
+ recently_uploaded_icon = WebDriverWait(self.driver, self.LONG_WAIT_IN_SEC).until(
+ ec.element_to_be_clickable((By.XPATH, "//div[@id='set0']//mi-box[1]//div"))
+ )
+ recently_uploaded_icon.click()
+
+ self.remove_color_from_icon()
+
+ if screenshot_folder:
+ screenshot_path = str(Path(screenshot_folder, f"screenshot_{index}.png").resolve())
+ self.driver.save_screenshot(screenshot_path)
+ print("Took screenshot and saved it at " + screenshot_path)
+
+ close_btn = self.driver \
+ .find_element_by_css_selector("div.overlayWindow i.icon-close")
+ close_btn.click()
def remove_color_from_icon(self):
"""
Remove the color from the most recent uploaded icon.
- :return: None.
+ This is because some SVG have colors in them and we don't want to
+ force contributors to remove them in case people want the colored SVGs.
+ The color removal is also necessary so that the Icomoon-generated
+ icons fit within one font symbol/ligiature.
"""
- try:
- recently_uploaded_icon = WebDriverWait(self.driver, self.LONG_WAIT_IN_SEC).until(
- ec.element_to_be_clickable((By.XPATH, "//div[@id='set0']//mi-box[1]//div"))
- )
- recently_uploaded_icon.click()
- except Exception as e:
- self.close()
- raise e
-
try:
color_tab = WebDriverWait(self.driver, self.SHORT_WAIT_IN_SEC).until(
ec.element_to_be_clickable((By.CSS_SELECTOR, "div.overlayWindow i.icon-droplet"))
@@ -217,42 +212,35 @@ def remove_color_from_icon(self):
.find_element_by_css_selector("div.overlayWindow i.icon-droplet-cross")
remove_color_btn.click()
except SeleniumTimeoutException:
- pass
- except Exception as e:
- self.close()
- raise e
-
- try:
- close_btn = self.driver \
- .find_element_by_css_selector("div.overlayWindow i.icon-close")
- close_btn.click()
- except Exception as e:
- self.close()
- raise e
+ pass # do nothing cause sometimes, the color tab doesn't appear in the site
def download_icomoon_fonts(self, zip_path: Path):
"""
Download the icomoon.zip from icomoon.io.
:param zip_path: the path to the zip file after it's downloaded.
"""
- try:
- print("Downloading Font files...")
- self.driver.find_element_by_css_selector(
- "a[href='#/select/font']"
- ).click()
-
- self.test_for_possible_alert(self.MED_WAIT_IN_SEC, "Continue")
- download_btn = WebDriverWait(self.driver, SeleniumRunner.LONG_WAIT_IN_SEC).until(
- ec.presence_of_element_located((By.CSS_SELECTOR, "button.btn4 span"))
- )
- download_btn.click()
- if self.wait_for_zip(zip_path):
- print("Font files downloaded.")
- else:
- raise TimeoutError(f"Couldn't find {zip_path} after download button was clicked.")
- except Exception as e:
- self.close()
- raise e
+ # select all the svgs so that the newly added svg are part of the collection
+ self.click_hamburger_input()
+ select_all_button = WebDriverWait(self.driver, self.LONG_WAIT_IN_SEC).until(
+ ec.element_to_be_clickable((By.XPATH, "//button[text()='Select All']"))
+ )
+ select_all_button.click()
+
+ print("Downloading Font files...")
+ font_tab = self.driver.find_element_by_css_selector(
+ "a[href='#/select/font']"
+ )
+ font_tab.click()
+
+ self.test_for_possible_alert(self.MED_WAIT_IN_SEC, "Continue")
+ download_btn = WebDriverWait(self.driver, SeleniumRunner.LONG_WAIT_IN_SEC).until(
+ ec.presence_of_element_located((By.CSS_SELECTOR, "button.btn4 span"))
+ )
+ download_btn.click()
+ if self.wait_for_zip(zip_path):
+ print("Font files downloaded.")
+ else:
+ raise TimeoutError(f"Couldn't find {zip_path} after download button was clicked.")
def wait_for_zip(self, zip_path: Path) -> bool:
"""
diff --git a/.github/scripts/build_assets/util.py b/.github/scripts/build_assets/arg_getters.py
similarity index 81%
rename from .github/scripts/build_assets/util.py
rename to .github/scripts/build_assets/arg_getters.py
index 1c31e7771..fe2893a23 100644
--- a/.github/scripts/build_assets/util.py
+++ b/.github/scripts/build_assets/arg_getters.py
@@ -1,8 +1,8 @@
-from pathlib import Path
from argparse import ArgumentParser
from build_assets.PathResolverAction import PathResolverAction
-def get_commandline_args():
+
+def get_selenium_runner_args(peek_mode=False):
parser = ArgumentParser(description="Upload svgs to Icomoon to create icon files.")
parser.add_argument("--headless",
@@ -26,8 +26,11 @@ def get_commandline_args():
action=PathResolverAction)
parser.add_argument("download_path",
- help="The path where you'd like to download the Icomoon files to",
+ help="The download destination of the Icomoon files",
action=PathResolverAction)
+ if peek_mode:
+ parser.add_argument("--pr_title",
+ help="The title of the PR that we are peeking at")
return parser.parse_args()
\ No newline at end of file
diff --git a/.github/scripts/build_assets/filehandler.py b/.github/scripts/build_assets/filehandler.py
index 6fc69920b..65a1234cd 100644
--- a/.github/scripts/build_assets/filehandler.py
+++ b/.github/scripts/build_assets/filehandler.py
@@ -145,3 +145,24 @@ def rename_extracted_files(extract_path: str):
os.replace(dict_["old"], dict_["new"])
print("Files renamed")
+
+
+def create_screenshot_folder(dir, screenshot_name: str="screenshots/"):
+ """
+ Create a screenshots folder in the dir.
+ :param dir, the dir where we want to create the folder.
+ :param screenshot_name, the name of the screenshot folder.
+ :raise Exception if the dir provided is not a directory.
+ :return the string name of the screenshot folder.
+ """
+ folder = Path(dir).resolve()
+ if not folder.is_dir():
+ raise Exception(f"This is not a dir: {str(folder)}. \ndir must be a valid directory")
+
+ screenshot_folder = Path(folder, screenshot_name)
+ try:
+ os.mkdir(screenshot_folder)
+ except FileExistsError:
+ print(f"{screenshot_folder} already exist. Script will do nothing.")
+ finally:
+ return str(screenshot_folder)
diff --git a/.github/scripts/generate_screenshot_markdown.py b/.github/scripts/generate_screenshot_markdown.py
new file mode 100644
index 000000000..e5a516132
--- /dev/null
+++ b/.github/scripts/generate_screenshot_markdown.py
@@ -0,0 +1,10 @@
+import json
+import os
+
+
+if __name__ == "__main__":
+ img_urls_list = json.loads(os.environ["IMG_URLS"])
+ template = "![Detailed Screenshot]({})"
+ markdown = [template.format(img_url) for img_url in img_urls_list]
+ print("\n\n".join(markdown))
+
diff --git a/.github/scripts/icomoon_build.py b/.github/scripts/icomoon_build.py
index 6b3eb352b..303a7ffc6 100644
--- a/.github/scripts/icomoon_build.py
+++ b/.github/scripts/icomoon_build.py
@@ -1,18 +1,18 @@
from pathlib import Path
+import sys
from selenium.common.exceptions import TimeoutException
# pycharm complains that build_assets is an unresolved ref
# don't worry about it, the script still runs
from build_assets.SeleniumRunner import SeleniumRunner
-from build_assets import filehandler, util
+from build_assets import filehandler, arg_getters
def main():
- args = util.get_commandline_args()
+ args = arg_getters.get_selenium_runner_args()
new_icons = filehandler.find_new_icons(args.devicon_json_path, args.icomoon_json_path)
if len(new_icons) == 0:
- print("No files need to be uploaded. Ending script...")
- return
+ sys.exit("No files need to be uploaded. Ending script...")
# print list of new icons
print("List of new icons:", *new_icons, sep = "\n")
@@ -32,10 +32,11 @@ def main():
filehandler.rename_extracted_files(args.download_path)
print("Task completed.")
except TimeoutException as e:
- print(e)
- print(e.stacktrace)
+ sys.exit("Selenium Time Out Error: \n" + str(e))
+ except Exception as e:
+ sys.exit(e)
finally:
- runner.close()
+ runner.close()
if __name__ == "__main__":
diff --git a/.github/scripts/icomoon_peek.py b/.github/scripts/icomoon_peek.py
index 6fd55f59c..cccfce5d7 100644
--- a/.github/scripts/icomoon_peek.py
+++ b/.github/scripts/icomoon_peek.py
@@ -1,32 +1,65 @@
+from typing import List
+import re
+import sys
from selenium.common.exceptions import TimeoutException
# pycharm complains that build_assets is an unresolved ref
# don't worry about it, the script still runs
from build_assets.SeleniumRunner import SeleniumRunner
-from build_assets import filehandler, util
+from build_assets import filehandler, arg_getters
def main():
- args = util.get_commandline_args()
+ args = arg_getters.get_selenium_runner_args(True)
new_icons = filehandler.find_new_icons(args.devicon_json_path, args.icomoon_json_path)
+
+ # get only the icon object that has the name matching the pr title
+ filtered_icons = find_object_added_in_this_pr(new_icons, args.pr_title)
+
if len(new_icons) == 0:
- print("No files need to be uploaded. Ending script...")
- return
+ sys.exit("No files need to be uploaded. Ending script...")
+
+ if len(filtered_icons) == 0:
+ message = "No icons found matching the icon name in the PR's title.\n" \
+ "Ensure that the PR title matches the convention here: \n" \
+ "https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#overview.\n" \
+ "Ending script...\n"
+ sys.exit(message)
# print list of new icons
print("List of new icons:", *new_icons, sep = "\n")
+ print("Icons being uploaded:", *filtered_icons, sep = "\n", end='\n\n')
runner = None
try:
runner = SeleniumRunner(args.download_path, args.geckodriver_path, args.headless)
- svgs = filehandler.get_svgs_paths(new_icons, args.icons_folder_path)
- runner.upload_svgs(svgs)
+ svgs = filehandler.get_svgs_paths(filtered_icons, args.icons_folder_path)
+ screenshot_folder = filehandler.create_screenshot_folder("./")
+ runner.upload_svgs(svgs, screenshot_folder)
print("Task completed.")
except TimeoutException as e:
- print(e)
- print(e.stacktrace)
+ sys.exit("Selenium Time Out Error: \n" + str(e))
+ except Exception as e:
+ sys.exit(e)
finally:
- runner.close()
+ runner.close()
+
+
+def find_object_added_in_this_pr(icons: List[dict], pr_title: str):
+ """
+ Find the icon name from the PR title.
+ :param icons, a list of the font objects found in the devicon.json.
+ :pr_title, the title of the PR that this workflow was called on.
+ :return a list containing the dictionary with the "name"
+ entry's value matching the name in the pr_title.
+ If none can be found, return an empty list.
+ """
+ try:
+ pattern = re.compile(r"(?<=^new icon: )\w+ (?=\(.+\))", re.I)
+ icon_name = pattern.findall(pr_title)[0].lower().strip() # should only have one match
+ return [icon for icon in icons if icon["name"] == icon_name]
+ except IndexError: # there are no match in the findall()
+ return []
if __name__ == "__main__":
diff --git a/.github/workflows/build_icons.yml b/.github/workflows/build_icons.yml
index 33a764e67..1cef6ed18 100644
--- a/.github/workflows/build_icons.yml
+++ b/.github/workflows/build_icons.yml
@@ -19,29 +19,42 @@ jobs:
pip install -r ./.github/scripts/requirements.txt
npm install
- name: Executing build and create fonts via icomoon
- run: npm run build
+ run: >
+ python ./.github/scripts/icomoon_build.py
+ ./.github/scripts/build_assets/geckodriver-v0.27.0-win64/geckodriver.exe ./icomoon.json
+ ./devicon.json ./icons ./ --headless
- name: Upload geckodriver.log for debugging purposes
uses: actions/upload-artifact@v2
- if: ${{failure()}}
+ if: failure()
with:
name: geckodriver-log
path: ./geckodriver.log
+ - name: Build devicon.min.css
+ if: success()
+ run: npm run build-css
- name: Upload screenshot of the newly made icons
- uses: actions/upload-artifact@v2
- if: ${{success()}}
+ id: imgur_step
+ uses: devicons/public-upload-to-imgur@v2.1
+ if: success()
with:
- name: new_icons
path: ./new_icons.png
- - name: Build devicon.min.css
- if: ${{ success() }}
- run: npm run build-css
+ client_id: ${{secrets.IMGUR_CLIENT_ID}}
- name: Create Pull Request
- if: ${{ success() }}
+ if: success()
uses: peter-evans/create-pull-request@v3
+ env:
+ MESSAGE: |
+ Automated font-building task ran by GitHub Actions bot. This PR built new font files and devicon.css file.
+
+ Here are all the files that were built:
+
+ ![Files Built]({0})
+
+ More information can be found in the GitHub Action logs for this workflow.
with:
branch: 'master-build-result'
base: 'master'
commit-message: 'Built new icons, icomoon.json and devicon.css'
title: 'bot:build new icons, icomoon.json and devicon.css'
- body: 'Automated font-building task ran by GitHub Actions bot'
+ body: ${{ format(env.MESSAGE, fromJSON(steps.imgur_step.outputs.imgur_url)[0] ) }}
delete-branch: true
diff --git a/.github/workflows/peek_icons.yml b/.github/workflows/peek_icons.yml
index 5bc2953a4..90ed6fbac 100644
--- a/.github/workflows/peek_icons.yml
+++ b/.github/workflows/peek_icons.yml
@@ -9,42 +9,101 @@ jobs:
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
- with:
- ref: ${{ github.head_ref }}
- repository: ${{ github.event.pull_request.head.repo.full_name}}
- name: Setup Python v3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- - name: Install dependencies (python, pip)
+ - name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r ./.github/scripts/requirements.txt
- name: Run icomoon_peek.py
- run: npm run peek
+ env:
+ PR_TITLE: ${{ github.event.pull_request.title }}
+ shell: cmd
+ run: >
+ python ./.github/scripts/icomoon_peek.py
+ ./.github/scripts/build_assets/geckodriver-v0.27.0-win64/geckodriver.exe ./icomoon.json
+ ./devicon.json ./icons ./ --headless --pr_title "%PR_TITLE%"
- name: Upload geckodriver.log for debugging purposes
uses: actions/upload-artifact@v2
- if: ${{failure()}}
+ if: failure()
with:
name: geckodriver-log
path: ./geckodriver.log
- name: Upload screenshot of the newly made icons
- uses: actions/upload-artifact@v2
- if: ${{success()}}
+ id: icons_overview_img_step
+ uses: devicons/public-upload-to-imgur@v2.1
+ if: success()
+ with:
+ path: ./screenshots/new_icons.png
+ client_id: ${{secrets.IMGUR_CLIENT_ID}}
+ - name: Upload zoomed in screenshot of the newly made icons
+ id: icons_detailed_img_step
+ uses: devicons/public-upload-to-imgur@v2.1
+ if: success()
with:
- name: new_icons
- path: ./new_icons.png
- # - name: Comment on the PR about the result
- # uses: github-actions-up-and-running/pr-comment@v1.0.1
- # with:
- # repo-token: ${{ secrets.GITHUB_TOKEN }}
- # message: >
- # Hi! I'm Devicons' GitHub Actions Bot!
-
- # I just peeked at the icons that you wanted to add and upload them to the
- # [Actions page](https://github.com/devicons/devicon/actions). The maintainers
- # will now take a look at it and decide whether to merge your PR.
-
- # Cheers :),
+ path: ./screenshots/screenshot_*.png
+ client_id: ${{secrets.IMGUR_CLIENT_ID}}
+ - name: Generate the markdowns for the screenshot and put it in the DETAILED_IMGS_MARKDOWN env var
+ if: success()
+ env:
+ IMG_URLS: ${{ steps.icons_detailed_img_step.outputs.imgur_urls }}
+ run: |
+ echo 'DETAILED_IMGS_MARKDOWN<> $GITHUB_ENV
+ python ./.github/scripts/generate_screenshot_markdown.py >> $GITHUB_ENV
+ echo 'EOF' >> $GITHUB_ENV
+ shell: bash
+ - name: Comment on the PR about the result
+ if: success()
+ uses: github-actions-up-and-running/pr-comment@v1.0.1
+ env:
+ OVERVIEW_IMG_URL: ${{ fromJSON(steps.icons_overview_img_step.outputs.imgur_urls)[0] }}
+ MESSAGE: |
+ Hi!
+
+ I'm Devicons' Peek Bot and I just peeked at the icons that you wanted to add using [icomoon.io](https://icomoon.io/app/#/select).
+ Here is the result below:
+
+ ![Peeked Icons (top left)]({0})
+
+ Here are the zoomed-in screenshots of the added icons:
+ {1}
+
+ Note: If the images don't show up, it's probably because it has been autodeleted by Imgur after 6 months due to our API choice.
+
+ The maintainers will now take a look at it and decide whether to merge your PR.
+
+ Thank you for contributing to Devicon! I hope everything works out and your icons are accepted into the repo.
+
+ Cheers :),
- # Bot
+ Peek Bot
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ message: ${{format(env.MESSAGE, env.OVERVIEW_IMG_URL, env.DETAILED_IMGS_MARKDOWN)}}
+ - name: Comment on the PR about the result
+ if: failure()
+ uses: github-actions-up-and-running/pr-comment@v1.0.1
+ env:
+ MESSAGE: |
+ Hi!
+
+ I'm Devicons' Peek Bot and it seems we've ran into a problem. I'm supposed to check your svgs but I couldn't do my task due to an issue.
+
+ Can you please double check and fix the possible issues below:
+
+ - Your svgs are named and added correctly to the /icons folder as seen [here](https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#orgGuidelines).
+ - Your icon information has been added to the `devicon.json` as seen [here](https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#updateDevicon)
+ - Your PR title follows the format seen [here](https://github.com/devicons/devicon/blob/master/CONTRIBUTING.md#overview)
+
+ Once everything is fixed, the maintainers will try again. If I still fail, the maintainers will investigate what cause this problem.
+
+ Thank you for your help :smile:
+
+ Cheers :),
+
+ Peek Bot
+ with:
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
+ message: ${{env.MESSAGE}}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3739a6653..a1aca5df9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -5,6 +5,7 @@ First of all, thanks for taking the time to contribute! This project can only gr
Create a separated pull request (PR) for each Icon.
+
Include the name of the Icon in the pull request title in this format: new icon: Icon name (versions)
+
Optional: Add images of the new svg(s) to the description of the pull request. This would help speed up the review process
Optional: Reference the issues regarding the new icon.
-
Wait for a repo maintainer to review your changes. They will run a script to check your icons.
+
Wait for a maintainer to review your changes. They will run a script to check your icons.
If there are no issue, they will accept your PR into the repo. Else, they will let you know and give you a chance to fix it.
Versions and Naming Conventions
-
Each icon can come in different versions. So far, we have:
+
Each icon/svg can come in different versions. So far, we have:
-
original: the original logo. Can contains multiple colors. Example
+
original: the original logo. Can contain multiple colors. Example
original-wordmark: similar to the above but must contain the name of the technology. Example
plain: a one-color version of the original logo. Example
plain-wordmark: a one-color version of the original logo but with wordmark. Example
line: a one-color, line version of the original logo. Example
line-wordmark: a one-color, line version of the original logo but with wordmark. Example
-
-It is not mandatory to have 6 versions for each icon. An icon can only have one or two versions available. Just keep in mind that the minimum is 1 and the maximum 6 (for now). You must also have at least one version that can be make into an icon.
-
-
-The plain and line versions (with or without wordmark) are designed to be available in the final icon font.
-
-
-The original version are only available in svg format, so they do not need to be as simple and can contain numerous colors.
-
-
-Some icons are really simple (like the Apple one), so the original version can be used as the plain version and as the icon font. In this case, you'll only need to make only one of the version (either "original" or "plain"). You can then add an alias in the devicon.json so they can be found with either the "original" or "plain" naming convention. Note that this only applies to font icon versions only, not the SVG versions. SVG versions don't need aliases.
-
+
Notes
+
+
+ You don't need to have 6 versions for each icon. An icon can only have one or two versions available. Just keep in mind that the minimum is 1 and the maximum 6 (for now). You must also have at least one version that can be make into an icon.
+
+
+ The plain and line versions (with or without wordmark) are designed to be available in the final icon font.
+
+
+ The original version are only available in svg format, so they do not need to be as simple and can contain numerous colors.
+
+
+ Some icons are really simple (ex. Apple), so the original version can be used as the plain version and as the icon font. In this case, you'll only need to make one of the version (either "original" or "plain"). You can then add an alias in the devicon.json so they can be found with either the "original" or "plain" naming convention. Note: this only applies to font icon versions only, not the SVG versions.
+
+
+
SVG Standards
Before you submit your logos/svgs, please ensure that they meet the following standard:
The background must be transparent.
-
The plain and line versions (with or without wordmark) need to stay as simple as possible. They must have only one color and the paths are united before exporting to svg.
+
The plain and line versions (with or without wordmark) need to stay as simple as possible. They must have only one color and the paths are united before exporting to svg. We will strip the color when turning it into icons.
Optimize/compress your SVGs. You can use a service like compressor or SVG Editor.
-
The icon's strokes and texts must be fills. We use Icomoon to make our icon, which has its requirements.
+
The icon's strokes and texts must be fills. This is to satisfy our conversion website's requirements.
Each .svg file contains one version of an icon in a 0 0 128 128 viewbox.
-
The naming convention for the svg file is the following: (icon name)-(original|plain|line)(-wordmark?).
+
Each .svg must use the fill attribute instead of using classes for colors. See here for more details.
+
The naming convention for the svg file is the following: (Icon name)-(original|plain|line)(-wordmark?).
Organizational Guidelines
Each icon has its own folder located in the icons folder
-
Each icon folder contains one .eps file and as many .svg files as versions available
-
The .eps file contains all available versions of an icon. Each version is contained in a 128px by 128px artboard
+
Each folder may contain one .eps file
(optional)
+
The .eps file should contains all available versions of an icon. Each version is contained in a 128px by 128px artboard
+
Each folder must contain all the .svg files for the Icon
Updating the devicon.json
- Before you open a PR into Devicon, you'd have to update the devicon.json. This is essential for our build script to work and to document your work.
+ Before you open a PR into Devicon, you must update the devicon.json. This is essential for our build script to work and to document your work.
- Here is the object that each of your logo must have:
+ Here is the object that each of your Icon must have:
@@ -103,7 +119,7 @@ Some icons are really simple (like the Apple one), so the original version can b
Here is what VersionString means:
-
It's the version part of an `svg` file's name
+
It's the version part of an svg file's name
If you have "html5-original", the version string would be "original"
If you have "react-line-wordmark", the version string would be "line-wordmark"
@@ -127,19 +143,19 @@ Some icons are really simple (like the Apple one), so the original version can b
As an example, let's assume you have created the svgs for Redhat and Amazon Web Services logos.
For the Redhat svg, you have the "original", "original-wordmark", "plain", and "plain-wordmark" versions.
-
For the Amazon Web Services svgs, you have the following versions: "original", "original-wordmark", "plain-wordmark". The "original" version is simple enough to be a "plain" version as well. Note that we are not using the acronym AWS.
+
For the Amazon Web Services svgs, you have the "original", "original-wordmark", "plain-wordmark" versions. The "original" version is simple enough to be a "plain" version as well. Note that we are not using the acronym AWS.
Put the svgs for each logo that you have into its own folders in /icons
This means you would create two folders: one for amazonwebservices and one for redhat
-
Note: don't do this in the same commits. We want to have each logo in its own PR so don't create these two folders in the same commit
+
Note: don't do this in the same commits; we want to have each Icon in its own PR.
{
@@ -193,17 +209,16 @@ As an example, let's assume you have created the svgs for Redhat and Amazon Web
{
"base": "original", // here is the base version that we will upload to Icomoon
"alias": "plain" // this is its alias. Our script will create a reference so users can search using "original" or "plain" for this icon
- // note that you don't provide aliases for the svg version. If "original" is not a font version (i.e can't be made into a font), there's no need to provide it with a plain alias
+ // note that you don't provide aliases for the svg version. If "original" can't be made into a font, there's no need to provide it with a plain alias
}
]
}
-
Note: again, don't do this in the same commits. We want to have each logo in its own PR so don't create two folders in the same commit
-
Create a separate pull request (PR) for each icon (no matter how many variations).
+
Create a separate pull request (PR) for each Icon.
This means you would have to create two PRs
For Amazon Web Services, the branch name would be icons/amazonwebservices.
@@ -211,7 +226,7 @@ As an example, let's assume you have created the svgs for Redhat and Amazon Web
- Include the name of the icon in the pull request. Follow this format: "new icon: {{logoName}} ({{versions}})"
+ Include the name of the icon in the pull request. Follow this format: "new icon: Icon name (versions}})"
For Amazon Web Services, your PR title should be "new icon: amazonwebservices (original, original-wordmark, plain-wordmark)"
For Redhat, your PR title should be "new icon: redhat (original, original-wordmark, plain, plain-wordmark)"
@@ -222,12 +237,12 @@ As an example, let's assume you have created the svgs for Redhat and Amazon Web
Requesting an Icon
-
When you want to request a new icon please feel free to create a issue following some simple guidelines:
+
To request an icon, you can create an issue in the repo. Please follow these simple guidelines:
Search for other issues already requesting the icon
If an issue doesn't exist, create an issue naming it "Icon request: name-of-the-icon".
-
Please create separated issues for each icon
-
optional: Include links where the icon can be found
+
Please create a separate issues for each icon
+
Optional: include links where the icon can be found
@@ -241,5 +256,6 @@ As an example, let's assume you have created the svgs for Redhat and Amazon Web
There are also other tasks that we are automating, such as:
Ensure code quality is up to standard
-
Upload svgs to icomoon.io and take a screenshot for check.
+
Upload svgs to icomoon.io and take a screenshot to check that it looks good.
+
Comment on the PR so maintainers don't have to manually upload icon result.
Devicon is a set of icons representing programming languages, designing & development tools. You can use it as a font or directly copy/paste the svg code into your project.
+
(Super) Quick Setup
+
First select an icon on the right, then select the version below and copy/paste the code into your project.
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/logos/android-chrome-144x144.png b/docs/logos/android-chrome-144x144.png
new file mode 100644
index 000000000..6e2ffc45d
Binary files /dev/null and b/docs/logos/android-chrome-144x144.png differ
diff --git a/docs/logos/android-chrome-192x192.png b/docs/logos/android-chrome-192x192.png
new file mode 100644
index 000000000..7ff1a5648
Binary files /dev/null and b/docs/logos/android-chrome-192x192.png differ
diff --git a/docs/logos/android-chrome-36x36.png b/docs/logos/android-chrome-36x36.png
new file mode 100644
index 000000000..d130b539e
Binary files /dev/null and b/docs/logos/android-chrome-36x36.png differ
diff --git a/docs/logos/android-chrome-48x48.png b/docs/logos/android-chrome-48x48.png
new file mode 100644
index 000000000..f65304991
Binary files /dev/null and b/docs/logos/android-chrome-48x48.png differ
diff --git a/docs/logos/android-chrome-72x72.png b/docs/logos/android-chrome-72x72.png
new file mode 100644
index 000000000..104660918
Binary files /dev/null and b/docs/logos/android-chrome-72x72.png differ
diff --git a/docs/logos/android-chrome-96x96.png b/docs/logos/android-chrome-96x96.png
new file mode 100644
index 000000000..a4d7559f1
Binary files /dev/null and b/docs/logos/android-chrome-96x96.png differ
diff --git a/docs/logos/apple-touch-icon-114x114.png b/docs/logos/apple-touch-icon-114x114.png
new file mode 100644
index 000000000..95f7ab1a0
Binary files /dev/null and b/docs/logos/apple-touch-icon-114x114.png differ
diff --git a/docs/logos/apple-touch-icon-120x120.png b/docs/logos/apple-touch-icon-120x120.png
new file mode 100644
index 000000000..4c56a264f
Binary files /dev/null and b/docs/logos/apple-touch-icon-120x120.png differ
diff --git a/docs/logos/apple-touch-icon-144x144.png b/docs/logos/apple-touch-icon-144x144.png
new file mode 100644
index 000000000..dc11d0d12
Binary files /dev/null and b/docs/logos/apple-touch-icon-144x144.png differ
diff --git a/docs/logos/apple-touch-icon-152x152.png b/docs/logos/apple-touch-icon-152x152.png
new file mode 100644
index 000000000..bd084940d
Binary files /dev/null and b/docs/logos/apple-touch-icon-152x152.png differ
diff --git a/docs/logos/apple-touch-icon-180x180.png b/docs/logos/apple-touch-icon-180x180.png
new file mode 100644
index 000000000..af389045d
Binary files /dev/null and b/docs/logos/apple-touch-icon-180x180.png differ
diff --git a/docs/logos/apple-touch-icon-57x57.png b/docs/logos/apple-touch-icon-57x57.png
new file mode 100644
index 000000000..381d190f6
Binary files /dev/null and b/docs/logos/apple-touch-icon-57x57.png differ
diff --git a/docs/logos/apple-touch-icon-60x60.png b/docs/logos/apple-touch-icon-60x60.png
new file mode 100644
index 000000000..a0bc25f84
Binary files /dev/null and b/docs/logos/apple-touch-icon-60x60.png differ
diff --git a/docs/logos/apple-touch-icon-72x72.png b/docs/logos/apple-touch-icon-72x72.png
new file mode 100644
index 000000000..c720d1d43
Binary files /dev/null and b/docs/logos/apple-touch-icon-72x72.png differ
diff --git a/docs/logos/apple-touch-icon-76x76.png b/docs/logos/apple-touch-icon-76x76.png
new file mode 100644
index 000000000..57f733000
Binary files /dev/null and b/docs/logos/apple-touch-icon-76x76.png differ
diff --git a/docs/logos/apple-touch-icon-precomposed.png b/docs/logos/apple-touch-icon-precomposed.png
new file mode 100644
index 000000000..91a9d077c
Binary files /dev/null and b/docs/logos/apple-touch-icon-precomposed.png differ
diff --git a/docs/logos/apple-touch-icon.png b/docs/logos/apple-touch-icon.png
new file mode 100644
index 000000000..af389045d
Binary files /dev/null and b/docs/logos/apple-touch-icon.png differ
diff --git a/docs/logos/favicon-16x16.png b/docs/logos/favicon-16x16.png
new file mode 100644
index 000000000..642eb90ae
Binary files /dev/null and b/docs/logos/favicon-16x16.png differ
diff --git a/docs/logos/favicon-32x32.png b/docs/logos/favicon-32x32.png
new file mode 100644
index 000000000..1bcfe6f9a
Binary files /dev/null and b/docs/logos/favicon-32x32.png differ
diff --git a/docs/logos/favicon-96x96.png b/docs/logos/favicon-96x96.png
new file mode 100644
index 000000000..a4d7559f1
Binary files /dev/null and b/docs/logos/favicon-96x96.png differ
diff --git a/docs/logos/favicon.ico b/docs/logos/favicon.ico
new file mode 100644
index 000000000..9ea1715a3
Binary files /dev/null and b/docs/logos/favicon.ico differ
diff --git a/docs/logos/mstile-144x144.png b/docs/logos/mstile-144x144.png
new file mode 100644
index 000000000..0dbf45e2f
Binary files /dev/null and b/docs/logos/mstile-144x144.png differ
diff --git a/docs/logos/mstile-150x150.png b/docs/logos/mstile-150x150.png
new file mode 100644
index 000000000..7015de63d
Binary files /dev/null and b/docs/logos/mstile-150x150.png differ
diff --git a/docs/logos/mstile-310x150.png b/docs/logos/mstile-310x150.png
new file mode 100644
index 000000000..8544b04ef
Binary files /dev/null and b/docs/logos/mstile-310x150.png differ
diff --git a/docs/logos/mstile-310x310.png b/docs/logos/mstile-310x310.png
new file mode 100644
index 000000000..f56755c3c
Binary files /dev/null and b/docs/logos/mstile-310x310.png differ
diff --git a/docs/logos/mstile-70x70.png b/docs/logos/mstile-70x70.png
new file mode 100644
index 000000000..f93136ece
Binary files /dev/null and b/docs/logos/mstile-70x70.png differ
diff --git a/docs/logos/safari-pinned-tab.svg b/docs/logos/safari-pinned-tab.svg
new file mode 100644
index 000000000..eeb0d3478
--- /dev/null
+++ b/docs/logos/safari-pinned-tab.svg
@@ -0,0 +1,320 @@
+
+
+
diff --git a/docs/manifest.json b/docs/manifest.json
new file mode 100644
index 000000000..eca47a649
--- /dev/null
+++ b/docs/manifest.json
@@ -0,0 +1,41 @@
+{
+ "name": "Devicon",
+ "icons": [
+ {
+ "src": "\/logos/android-chrome-36x36.png",
+ "sizes": "36x36",
+ "type": "image\/png",
+ "density": "0.75"
+ },
+ {
+ "src": "\/logos/android-chrome-48x48.png",
+ "sizes": "48x48",
+ "type": "image\/png",
+ "density": "1.0"
+ },
+ {
+ "src": "\/logos/android-chrome-72x72.png",
+ "sizes": "72x72",
+ "type": "image\/png",
+ "density": "1.5"
+ },
+ {
+ "src": "\/logos/android-chrome-96x96.png",
+ "sizes": "96x96",
+ "type": "image\/png",
+ "density": "2.0"
+ },
+ {
+ "src": "\/logos/android-chrome-144x144.png",
+ "sizes": "144x144",
+ "type": "image\/png",
+ "density": "3.0"
+ },
+ {
+ "src": "\/logos/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image\/png",
+ "density": "4.0"
+ }
+ ]
+}
diff --git a/gulpfile.js b/gulpfile.js
index 2422acd5f..1541ffc10 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -141,7 +141,6 @@ function cleanUp() {
let filePath = path.join(__dirname, name);
return fsPromise.unlink(filePath);
} catch(e) {
- console.log("err was catch here");
console.log(e);
}
})
@@ -150,4 +149,4 @@ function cleanUp() {
exports.updateCss = createDeviconMinCSS;
-exports.clean = cleanUp;
\ No newline at end of file
+exports.clean = cleanUp;
diff --git a/icons/aftereffects/aftereffects-original.svg b/icons/aftereffects/aftereffects-original.svg
index a3836e549..952ac8a97 100644
--- a/icons/aftereffects/aftereffects-original.svg
+++ b/icons/aftereffects/aftereffects-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/aftereffects/aftereffects-plain.svg b/icons/aftereffects/aftereffects-plain.svg
index 66979bf3b..c6343a310 100644
--- a/icons/aftereffects/aftereffects-plain.svg
+++ b/icons/aftereffects/aftereffects-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/babel/babel-original.svg b/icons/babel/babel-original.svg
index af7b38b68..b1301c4e8 100644
--- a/icons/babel/babel-original.svg
+++ b/icons/babel/babel-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/babel/babel-plain.svg b/icons/babel/babel-plain.svg
index e6ba7a0a5..4f28c1f49 100644
--- a/icons/babel/babel-plain.svg
+++ b/icons/babel/babel-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/bash/bash-original.svg b/icons/bash/bash-original.svg
new file mode 100644
index 000000000..64b7cbfac
--- /dev/null
+++ b/icons/bash/bash-original.svg
@@ -0,0 +1,28 @@
+
\ No newline at end of file
diff --git a/icons/bash/bash-plain.svg b/icons/bash/bash-plain.svg
new file mode 100644
index 000000000..71c66f349
--- /dev/null
+++ b/icons/bash/bash-plain.svg
@@ -0,0 +1,46 @@
+
+
\ No newline at end of file
diff --git a/icons/bash/bash.eps b/icons/bash/bash.eps
new file mode 100644
index 000000000..5596f4a61
Binary files /dev/null and b/icons/bash/bash.eps differ
diff --git a/icons/behance/behance-original-wordmark.svg b/icons/behance/behance-original-wordmark.svg
index 3bfa7171c..05f3fd6c4 100644
--- a/icons/behance/behance-original-wordmark.svg
+++ b/icons/behance/behance-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/behance/behance-original.svg b/icons/behance/behance-original.svg
index cc975ddcb..acd1af5da 100644
--- a/icons/behance/behance-original.svg
+++ b/icons/behance/behance-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/behance/behance-plain-wordmark.svg b/icons/behance/behance-plain-wordmark.svg
index ca65c8f34..e7f6e3ab8 100644
--- a/icons/behance/behance-plain-wordmark.svg
+++ b/icons/behance/behance-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/behance/behance-plain.svg b/icons/behance/behance-plain.svg
index a1ce4b5ed..f2136ead2 100644
--- a/icons/behance/behance-plain.svg
+++ b/icons/behance/behance-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/cakephp/cakephp-original-wordmark.svg b/icons/cakephp/cakephp-original-wordmark.svg
index 3f19d90d5..0a52b8bc6 100644
--- a/icons/cakephp/cakephp-original-wordmark.svg
+++ b/icons/cakephp/cakephp-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/cakephp/cakephp-original.svg b/icons/cakephp/cakephp-original.svg
index ead4c6c2c..37558eb46 100644
--- a/icons/cakephp/cakephp-original.svg
+++ b/icons/cakephp/cakephp-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/cakephp/cakephp-plain-wordmark.svg b/icons/cakephp/cakephp-plain-wordmark.svg
index 1ab776ebf..55166dd15 100644
--- a/icons/cakephp/cakephp-plain-wordmark.svg
+++ b/icons/cakephp/cakephp-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/cakephp/cakephp-plain.svg b/icons/cakephp/cakephp-plain.svg
index a675c8e82..e37176997 100644
--- a/icons/cakephp/cakephp-plain.svg
+++ b/icons/cakephp/cakephp-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/ceylon/ceylon-original-wordmark.svg b/icons/ceylon/ceylon-original-wordmark.svg
index 778c7f315..cda2521cc 100644
--- a/icons/ceylon/ceylon-original-wordmark.svg
+++ b/icons/ceylon/ceylon-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/ceylon/ceylon-original.svg b/icons/ceylon/ceylon-original.svg
index 5bb3f4f87..e6ea3cde1 100644
--- a/icons/ceylon/ceylon-original.svg
+++ b/icons/ceylon/ceylon-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/ceylon/ceylon-plain-wordmark.svg b/icons/ceylon/ceylon-plain-wordmark.svg
index b13cab4a1..1666b4ee0 100644
--- a/icons/ceylon/ceylon-plain-wordmark.svg
+++ b/icons/ceylon/ceylon-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/ceylon/ceylon-plain.svg b/icons/ceylon/ceylon-plain.svg
index 5c70fb222..4c12db253 100644
--- a/icons/ceylon/ceylon-plain.svg
+++ b/icons/ceylon/ceylon-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/couchdb/couchdb-original-wordmark.svg b/icons/couchdb/couchdb-original-wordmark.svg
index c2ca9f2d5..8ee76892b 100644
--- a/icons/couchdb/couchdb-original-wordmark.svg
+++ b/icons/couchdb/couchdb-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/couchdb/couchdb-original.svg b/icons/couchdb/couchdb-original.svg
index 1a9df6b20..ff88946f7 100644
--- a/icons/couchdb/couchdb-original.svg
+++ b/icons/couchdb/couchdb-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/couchdb/couchdb-plain-wordmark.svg b/icons/couchdb/couchdb-plain-wordmark.svg
index 95104870f..05a8190d1 100644
--- a/icons/couchdb/couchdb-plain-wordmark.svg
+++ b/icons/couchdb/couchdb-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/couchdb/couchdb-plain.svg b/icons/couchdb/couchdb-plain.svg
index a71c70671..add01e759 100644
--- a/icons/couchdb/couchdb-plain.svg
+++ b/icons/couchdb/couchdb-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/cucumber/cucumber-plain-wordmark.svg b/icons/cucumber/cucumber-plain-wordmark.svg
index 7971734e1..f6310cd79 100644
--- a/icons/cucumber/cucumber-plain-wordmark.svg
+++ b/icons/cucumber/cucumber-plain-wordmark.svg
@@ -2,11 +2,7 @@
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/devicon/devicon-original.svg b/icons/devicon/devicon-original.svg
index 3988e71c5..1ca664776 100644
--- a/icons/devicon/devicon-original.svg
+++ b/icons/devicon/devicon-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/devicon/devicon-plain-wordmark.svg b/icons/devicon/devicon-plain-wordmark.svg
index d85245f1a..e6fdda323 100644
--- a/icons/devicon/devicon-plain-wordmark.svg
+++ b/icons/devicon/devicon-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/devicon/devicon-plain.svg b/icons/devicon/devicon-plain.svg
index b342e04b3..798628c28 100644
--- a/icons/devicon/devicon-plain.svg
+++ b/icons/devicon/devicon-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/electron/electron-original-wordmark.svg b/icons/electron/electron-original-wordmark.svg
index a8de91726..9d5c90df6 100644
--- a/icons/electron/electron-original-wordmark.svg
+++ b/icons/electron/electron-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/electron/electron-original.svg b/icons/electron/electron-original.svg
index 845baeade..9fdf44ff4 100644
--- a/icons/electron/electron-original.svg
+++ b/icons/electron/electron-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/elm/elm-original-wordmark.svg b/icons/elm/elm-original-wordmark.svg
index 06337d5b4..7345d227c 100644
--- a/icons/elm/elm-original-wordmark.svg
+++ b/icons/elm/elm-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/elm/elm-original.svg b/icons/elm/elm-original.svg
index e7183fb33..ceccdeba1 100644
--- a/icons/elm/elm-original.svg
+++ b/icons/elm/elm-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/elm/elm-plain-wordmark.svg b/icons/elm/elm-plain-wordmark.svg
index 475a04723..d94da3224 100644
--- a/icons/elm/elm-plain-wordmark.svg
+++ b/icons/elm/elm-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/elm/elm-plain.svg b/icons/elm/elm-plain.svg
index cfeaddacc..2a0615517 100644
--- a/icons/elm/elm-plain.svg
+++ b/icons/elm/elm-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/ember/ember-original-wordmark.svg b/icons/ember/ember-original-wordmark.svg
index f0d141f6c..7178ca369 100644
--- a/icons/ember/ember-original-wordmark.svg
+++ b/icons/ember/ember-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/facebook/facebook-original.svg b/icons/facebook/facebook-original.svg
index c7584f04e..10e5117c8 100644
--- a/icons/facebook/facebook-original.svg
+++ b/icons/facebook/facebook-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/facebook/facebook-plain.svg b/icons/facebook/facebook-plain.svg
index 3e30b5a4e..d51fa53cf 100644
--- a/icons/facebook/facebook-plain.svg
+++ b/icons/facebook/facebook-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/flutter/flutter-original.svg b/icons/flutter/flutter-original.svg
index 125bde63f..c9c483547 100644
--- a/icons/flutter/flutter-original.svg
+++ b/icons/flutter/flutter-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/flutter/flutter-plain.svg b/icons/flutter/flutter-plain.svg
index d5659a85d..b453881cc 100644
--- a/icons/flutter/flutter-plain.svg
+++ b/icons/flutter/flutter-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/gatling/gatling-plain-wordmark.svg b/icons/gatling/gatling-plain-wordmark.svg
index af60e63e5..970a8d396 100644
--- a/icons/gatling/gatling-plain-wordmark.svg
+++ b/icons/gatling/gatling-plain-wordmark.svg
@@ -2,10 +2,7 @@
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/gatsby/gatsby-original.svg b/icons/gatsby/gatsby-original.svg
index c888c2976..b4e7df095 100644
--- a/icons/gatsby/gatsby-original.svg
+++ b/icons/gatsby/gatsby-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/gatsby/gatsby-plain-wordmark.svg b/icons/gatsby/gatsby-plain-wordmark.svg
index eb4fb8093..bb75ec1f9 100644
--- a/icons/gatsby/gatsby-plain-wordmark.svg
+++ b/icons/gatsby/gatsby-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/gatsby/gatsby-plain.svg b/icons/gatsby/gatsby-plain.svg
index c888c2976..b4e7df095 100644
--- a/icons/gatsby/gatsby-plain.svg
+++ b/icons/gatsby/gatsby-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/google/google-original-wordmark.svg b/icons/google/google-original-wordmark.svg
index 67bb73007..ffcfb8ff3 100644
--- a/icons/google/google-original-wordmark.svg
+++ b/icons/google/google-original-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/google/google-original.svg b/icons/google/google-original.svg
index b39734d99..6b4844be0 100644
--- a/icons/google/google-original.svg
+++ b/icons/google/google-original.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/google/google-plain-wordmark.svg b/icons/google/google-plain-wordmark.svg
index 8bd4791cb..a2f2f2f4b 100644
--- a/icons/google/google-plain-wordmark.svg
+++ b/icons/google/google-plain-wordmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/google/google-plain.svg b/icons/google/google-plain.svg
index 44b6e93b4..e87a0e89b 100644
--- a/icons/google/google-plain.svg
+++ b/icons/google/google-plain.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/icons/gradle/gradle-plain-wordmark.svg b/icons/gradle/gradle-plain-wordmark.svg
index 520d3fe54..19b0af741 100644
--- a/icons/gradle/gradle-plain-wordmark.svg
+++ b/icons/gradle/gradle-plain-wordmark.svg
@@ -2,10 +2,7 @@