Google publishes 67 symbols per cut (auto_awesome, insights, tips_and_updates, battery_50 ...) with width and height but no viewBox, their paths in 24 units, or 20 in the 20 cut, where every other symbol draws in `0 -960 960 960`. bin/fetch-symbols dropped the size so CSS decides it, which left these with no coordinate system: `<x-icon>` drew them at 1:1, whole only at exactly 24px and cut off or misplaced at any other size, the 20 cut every small button uses included. normalise() now turns a file's width and height into its viewBox when it has none, before dropping them. The 268 files are regenerated from Google's originals at the recorded SOURCE commit with the fixed step (each shipped file matched the old step's output first; the other 16,272 do not change), and every path lies inside its new viewBox. IconTest checks that each shipped symbol has a viewBox and that `<x-icon name="auto_awesome">` renders in 20 units at size 16 and in 24 at size 32; both fail without the change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
92 lines
3.6 KiB
Bash
Executable File
92 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Refresh resources/svg/symbols from google/material-design-icons (Apache-2.0).
|
|
#
|
|
# Material Symbols Rounded at weight 400 and grade 0, outlined and filled, in two cuts:
|
|
# optical size 24 (the standard size) and optical size 20. M3 draws an icon at 20 dp or
|
|
# smaller from the 20 cut, whose strokes stay as heavy as the 24 dp design's instead of
|
|
# thinning as the glyph is scaled down (docs/reference/m3/styles.md § Icons, the optical
|
|
# size axis). Maintenance only: applications never run this, and bin/ is not part of the
|
|
# archive Composer installs.
|
|
#
|
|
# The repository is ~5 GB, so it is cloned without blobs and checked out sparsely:
|
|
# git downloads only the four files per symbol that are kept. The @material-symbols
|
|
# npm packages were not used because their SVGs are drawn at optical size 48, whose
|
|
# strokes are thinner than the 24px design.
|
|
|
|
set -euo pipefail
|
|
|
|
root="$(cd "$(dirname "$0")/.." && pwd)"
|
|
work="$(mktemp -d)"
|
|
trap 'rm -rf "$work"' EXIT
|
|
|
|
git clone --quiet --depth=1 --filter=blob:none --no-checkout \
|
|
https://github.com/google/material-design-icons.git "$work/repo"
|
|
|
|
cd "$work/repo"
|
|
|
|
git sparse-checkout set --no-cone \
|
|
'/symbols/web/*/materialsymbolsrounded/*_24px.svg' \
|
|
'/symbols/web/*/materialsymbolsrounded/*_20px.svg' \
|
|
'!/symbols/web/*/materialsymbolsrounded/*_wght[0-9]*' \
|
|
'!/symbols/web/*/materialsymbolsrounded/*_grad200*' \
|
|
'!/symbols/web/*/materialsymbolsrounded/*_gradN25*'
|
|
|
|
git checkout --quiet "$(git symbolic-ref --short HEAD)"
|
|
|
|
out="$root/resources/svg/symbols"
|
|
|
|
# The 24 cut keeps the folder names it has always had; the 20 cut is suffixed, so a
|
|
# name resolves to a folder without a lookup table (Support\SvgFile::symbol()).
|
|
folder() { # optical size, style
|
|
case "$1" in
|
|
24) echo "$out/$2" ;;
|
|
*) echo "$out/$2-$1" ;;
|
|
esac
|
|
}
|
|
|
|
for size in 24 20; do
|
|
for style in outlined filled; do
|
|
rm -rf "$(folder "$size" "$style")"
|
|
mkdir -p "$(folder "$size" "$style")"
|
|
done
|
|
done
|
|
|
|
# Google's files carry width="24" height="24" and no fill. Drop the size so CSS decides
|
|
# it, and paint in currentColor so an icon takes the colour of the text around it. Nearly
|
|
# every file draws in a viewBox="0 -960 960 960"; a few carry none and draw in the units of
|
|
# their width and height (24, or 20 in the 20 cut), so the size becomes their viewBox before
|
|
# it goes, or the glyph would only fit at exactly that many pixels.
|
|
normalise() {
|
|
sed -E \
|
|
-e '/viewBox=/!s/<svg ([^>]*)height="([0-9]+)(px)?"([^>]*)width="([0-9]+)(px)?"/<svg \1height="\2"\4width="\5" viewBox="0 0 \5 \2"/' \
|
|
-e '/viewBox=/!s/<svg ([^>]*)width="([0-9]+)(px)?"([^>]*)height="([0-9]+)(px)?"/<svg \1width="\2"\4height="\5" viewBox="0 0 \2 \5"/' \
|
|
-e 's/ (width|height)="[0-9]+(px)?"//g' \
|
|
-e 's/<svg /<svg fill="currentColor" /' \
|
|
"$1"
|
|
}
|
|
|
|
missing=0
|
|
|
|
for dir in symbols/web/*/materialsymbolsrounded; do
|
|
name="$(basename "$(dirname "$dir")")"
|
|
|
|
for size in 24 20; do
|
|
outlined="$dir/${name}_${size}px.svg"
|
|
filled="$dir/${name}_fill1_${size}px.svg"
|
|
|
|
if [[ ! -f "$outlined" || ! -f "$filled" ]]; then
|
|
echo "skipped $name: no outlined and filled ${size}px pair" >&2
|
|
missing=$((missing + 1))
|
|
continue
|
|
fi
|
|
|
|
normalise "$outlined" > "$(folder "$size" outlined)/$name.svg"
|
|
normalise "$filled" > "$(folder "$size" filled)/$name.svg"
|
|
done
|
|
done
|
|
|
|
git rev-parse HEAD > "$out/SOURCE"
|
|
|
|
echo "$(ls "$out/outlined" | wc -l | tr -d ' ') symbols at optical size 24 and $(ls "$out/outlined-20" | wc -l | tr -d ' ') at 20 from google/material-design-icons@$(cut -c1-12 "$out/SOURCE"), $missing skipped"
|