Skip to content

Commit

Permalink
Bumped to Iconify JSON with datestamp 2024-11-16. Additional changs t…
Browse files Browse the repository at this point in the history
…o remove defined paths and to be dynamically generated.
  • Loading branch information
beecho01 committed Nov 17, 2024
1 parent 160f21e commit 1296eb0
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 113 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<h1 align="center">Material Symbols for Home Assistant</h1>
</div>

**Material Symbols for Home Assistant** is a collection of 13482 Google Material Symbols for use within Home Assistant. It uses the icon-set produced and maintained by [iconify](https://github.com/iconify/icon-sets).
**Material Symbols for Home Assistant** is a collection of 13,616 Google Material Symbols for use within Home Assistant. It uses the icon-set produced and maintained by [iconify](https://github.com/iconify/icon-sets).

There is a [Icon Finder Tool](https://beecho01.github.io/material-symbols-iconfinder/) to help you select the correct icon. Simply type in what you're looking for, click the icon of choice, and the icon entry for home assistant will be copied to your clipboard (e.g., `m3o:light`). The copied text can be pasted for use in your YAML configuration or into you UI frontend interface.

Expand All @@ -17,7 +17,7 @@ There is a [Icon Finder Tool](https://beecho01.github.io/material-symbols-iconfi
> ### Breaking Changes
> - **Repository Structure**: The repository and installation have transitioned from a "Lovelace" repository (v1.X.X) to an "Integration" repository (202X.X.X+). Users should reinstall from the new integration repository to avoid compatibility issues.
> - **Icon Prefix Migration**: The icon prefix has transitioned from m3s, which previously contained all icon styles, to individual prefixes based on style. Each style now has its unique prefix (e.g., m3o for outlined, m3r for rounded). Refer to the documentation for the complete list of prefixes.
> - **Reduction in Available Icons**: The number of available icons has been reduced from ~18,600 to 13,482.
> - **Reduction in Available Icons**: The number of available icons has been reduced from ~18,600 to 13,616.
---

Expand Down
2 changes: 1 addition & 1 deletion custom_components/material_symbols/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
LOGGER = logging.getLogger(__name__)

DOMAIN = "material_symbols"
VERSION = "2024.11.02"
VERSION = "2024.11.17"

DATA_EXTRA_MODULE_URL = "frontend_extra_module_url"
LOADER_URL = f"/{DOMAIN}/material_symbols.js"
Expand Down
51 changes: 0 additions & 51 deletions custom_components/material_symbols/data/extract_names.py

This file was deleted.

64 changes: 31 additions & 33 deletions custom_components/material_symbols/data/generate_svgs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# Constants for the folder paths
FOLDERS = {
"outlined": "m3o",
"outline": "m3o",
"outline-rounded": "m3r",
"outline-sharp": "m3s",
"rounded": "m3rf",
Expand All @@ -15,7 +15,7 @@

# Remove existing folders and create new ones
def create_folders(base_path):
for folder in FOLDERS.values():
for folder in set(FOLDERS.values()):
folder_path = os.path.join(base_path, folder)
if os.path.exists(folder_path):
shutil.rmtree(folder_path)
Expand All @@ -31,68 +31,66 @@ def fetch_json(url):
else:
raise Exception(f"Failed to fetch JSON data. Status code: {response.status_code}")

# Strip the suffix from the name
# Strip the suffix from the icon name
def strip_suffix(name):
suffixes = ["-outline", "-outline-rounded", "-outline-sharp", "-rounded", "-sharp"]
for suffix in suffixes:
if name.endswith(suffix):
return name[:-len(suffix)]
return name

# Determine the folder based on the icon name
def get_folder(name):
if name.endswith("outline"):
return name.replace("-outline", "")
return FOLDERS["outline"]
elif name.endswith("outline-rounded"):
return name.replace("-outline-rounded", "")
return FOLDERS["outline-rounded"]
elif name.endswith("outline-sharp"):
return name.replace("-outline-sharp", "")
elif name.endswith("-rounded"):
return name.replace("-rounded", "")
elif name.endswith("-sharp"):
return name.replace("-sharp", "")
return FOLDERS["outline-sharp"]
elif name.endswith("rounded"):
return FOLDERS["rounded"]
elif name.endswith("sharp"):
return FOLDERS["sharp"]
else:
return name
return FOLDERS["default"]

# Export SVG files and collect icon names by folder
def export_svgs(base_path, icons):
icon_names_by_folder = {folder: [] for folder in FOLDERS.values()}
icon_names_by_folder = {folder: set() for folder in set(FOLDERS.values())}
for name, data in icons.items():
svg_body = data["body"].replace('\"', '"')
svg_content = f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">{svg_body}</svg>'

if name.endswith("outline"):
folder = FOLDERS["outlined"]
elif name.endswith("outline-rounded"):
folder = FOLDERS["outline-rounded"]
elif name.endswith("outline-sharp"):
folder = FOLDERS["outline-sharp"]
elif name.endswith("rounded"):
folder = FOLDERS["rounded"]
elif name.endswith("sharp"):
folder = FOLDERS["sharp"]
else:
folder = FOLDERS["default"]

folder = get_folder(name)
base_name = strip_suffix(name)
file_path = os.path.join(base_path, folder, f"{base_name}.svg")

with open(file_path, "w") as svg_file:
svg_file.write(svg_content)
print(f"Exported {base_name}.svg to {folder}")

# Track icon name for JSON output
icon_names_by_folder[folder].append(base_name)

# Generate JSON files for each folder
# Add the icon name to the set for JSON generation
icon_names_by_folder[folder].add(base_name)

# Generate icons.json files for each folder
for folder, icons in icon_names_by_folder.items():
create_icon_json(base_path, folder, icons)

# Create a JSON file listing all icons in a folder
def create_icon_json(base_path, folder, icons):
icons_data = [{"name": icon} for icon in icons]
icons_data = [{"name": icon} for icon in sorted(icons)]
json_path = os.path.join(base_path, folder, "icons.json")
with open(json_path, "w") as json_file:
json.dump(icons_data, json_file, indent=4)
print(f"Created JSON for {folder} with {len(icons)} icons")
print(f"Created icons.json for {folder} with {len(icons)} icons")

# Main function
def main():
url = "https://raw.githubusercontent.com/iconify/icon-sets/refs/heads/master/json/material-symbols.json"
base_path = r"C:\Github\material-symbols\custom_components\material_symbols\data" # Specify your output folder


# Use the current working directory as the base path
base_path = os.getcwd()

create_folders(base_path)
json_data = fetch_json(url)
icons = json_data.get("icons", {})
Expand Down
2 changes: 1 addition & 1 deletion custom_components/material_symbols/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/beecho01/material-symbols/issues",
"requirements": [],
"version": "2024.11.02"
"version": "2024.11.17"
}
53 changes: 28 additions & 25 deletions custom_components/material_symbols/material_symbols.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
(() => {
"use strict";

// Base path
// Base path
const a = "material_symbols";

// Determine the base URL
const baseUrl = (typeof hass !== 'undefined' && hass.auth && hass.auth.data && hass.auth.data.hassUrl)
? hass.auth.data.hassUrl
: window.location.origin;

// Ensure baseUrl ends with a slash
const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;

// Cache for loaded icons.json files
const iconCache = {};

Expand All @@ -13,26 +21,25 @@
// Load icons.json for a given icon set if not already cached
const loadIconSet = async (iconsetPrefix) => {
if (!iconCache[iconsetPrefix]) {

try {
// Construct the correct URL using baseUrl
const url = `${normalizedBaseUrl}/${a}/${iconsetPrefix}/icons.json`;

// Fetch icons.json
const response = await fetch(`/${a}/${iconsetPrefix}/icons.json`);
if (!response.ok) throw new Error(`Failed to fetch icons.json for ${iconsetPrefix}`);

// Read as array and map to icon names
const response = await fetch(url);
if (!response.ok) {
const errorText = await response.text();
console.error(`Failed to fetch icons.json for ${iconsetPrefix}. Status: ${response.status}. Response: ${errorText}`);
throw new Error(`Failed to fetch icons.json for ${iconsetPrefix}`);
}

// Parse the JSON response
const icons = await response.json();
iconCache[iconsetPrefix] = icons.map(icon => icon.name);
// console.log(`Loaded icons for ${iconsetPrefix}:`, iconCache[iconsetPrefix]);

} catch (error) {

// Failed to load icons.json
// console.error(`Error loading icon set ${iconsetPrefix}:`, error);
console.error(`Error loading icon set ${iconsetPrefix}:`, error);
iconCache[iconsetPrefix] = [];
}
}
// Return icon list
return iconCache[iconsetPrefix];
};

Expand All @@ -51,17 +58,19 @@
}

try {
// Construct the correct URL using baseUrl
const url = `${normalizedBaseUrl}/${a}/${iconsetPrefix}/${iconName}.svg`;

// Fetch SVG
const response = await fetch(`/${a}/${iconsetPrefix}/${iconName}.svg`);
const response = await fetch(url);
if (!response.ok) {
console.error(`Failed to fetch icon "${iconName}" from icon set "${iconsetPrefix}".`);
const errorText = await response.text();
console.error(`Failed to fetch icon "${iconName}" from icon set "${iconsetPrefix}". Status: ${response.status}. Response: ${errorText}`);
return '';
}

// Parse SVG
const svgText = await response.text();
const doc = new DOMParser().parseFromString(svgText, "text/html");
const doc = new DOMParser().parseFromString(svgText, "image/svg+xml");
const svgElement = doc.querySelector("svg");
if (!svgElement) return '';

Expand All @@ -75,8 +84,6 @@
return iconObject;

} catch (error) {

// Console error if failed to load SVG
console.error("Error fetching icon:", error);
return '';
}
Expand All @@ -93,7 +100,6 @@

// Register icon sets for each prefix
["m3o", "m3of", "m3r", "m3rf", "m3s", "m3sf"].forEach((prefix) => {

// Register the icon set with Home Assistant's custom icon API
window.customIconsets[prefix] = (iconName) => getIcon(prefix, iconName);

Expand All @@ -102,15 +108,12 @@
getIcon: (iconName) => getIcon(prefix, iconName),
getIconList: () => getIconList(prefix),
};

// console.log(`Registered icon set: ${prefix}`);

});

console.info(
"%c MATERIAL SYMBOLS %c %c 2024.11.02 ",
"%c MATERIAL SYMBOLS %c %c 2024.11.17 ",
'@import url("https://fonts.googleapis.com/css2?family=Roboto");background-color:#1FBEF2;color:#FFFFFF;padding:3px 43px 2px 8px;border-radius:999vh;border:5px solid #1FBEF2;font-family:"Roboto", sans-serif;margin-top:18px',
'@import url("https://fonts.googleapis.com/css2?family=Roboto");background-color:#FFFFFF;color:#1FBEF2;padding:3px 8px 2px 0;border-radius:999vh 0 0 999vh;border:0;font-family:"Roboto", sans-serif;margin-left:-94px',
'@import url("https://fonts.googleapis.com/css2?family=Roboto");background-color:#FFFFFF;color:#1FBEF2;padding:3px 9px 2px 0;border-radius:0 999vh 999vh 0;border:0;font-family:"Roboto", sans-serif;margin-left:-1px;margin-bottom:18px'
);
})();
})();

0 comments on commit 1296eb0

Please sign in to comment.