From f31b3743709c0dd19699749cc976248ff264b516 Mon Sep 17 00:00:00 2001 From: Michael Zetterberg Date: Sun, 6 Apr 2025 05:41:34 +0200 Subject: [PATCH] feat: optimize Material Symbols --- README.md | 26 ++ apps/scandic-web/README.md | 4 + apps/scandic-web/app/[lang]/(live)/layout.tsx | 1 - .../app/[lang]/(live-current)/layout.tsx | 1 - .../app/[lang]/(partner)/layout.tsx | 1 - .../scandic-web/app/[lang]/webview/layout.tsx | 1 - .../material-symbols/rounded-eaec15a9.woff2 | Bin 0 -> 25132 bytes package.json | 3 +- packages/design-system/README.md | 4 +- .../Icons/MaterialIcon/MaterialIcon.tsx | 18 +- packages/design-system/lib/fonts.css | 29 ++ .../material-symbols/rounded-eaec15a9.woff2 | Bin 0 -> 25132 bytes scripts/material-symbols-update.mjs | 277 ++++++++++++++++++ 13 files changed, 343 insertions(+), 22 deletions(-) create mode 100644 apps/scandic-web/public/_static/fonts/material-symbols/rounded-eaec15a9.woff2 create mode 100644 packages/design-system/public/_static/fonts/material-symbols/rounded-eaec15a9.woff2 create mode 100644 scripts/material-symbols-update.mjs diff --git a/README.md b/README.md index 29c162fad..40371e568 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,29 @@ To get started, clone this repository and run `yarn install` in the root directo ### Running `scandic-web` locally To run the `scandic-web` app locally see its [README](./apps/scandic-web/README.md). + +## Material Symbols + +We download the font file from Google Fonts service and host it ourselves. + +### Configuration + +We use the following configuration: + +- FILL axis: 0..1 +- wght axis: 400 +- GRAD axis: 0 +- opsz axis: 24 + +More info at https://developers.google.com/fonts/docs/material_symbols#optimize_the_icon_font + +### Optimization + +We optimize the font size by only including the icons we use in the repository. + +Read more at: https://developers.google.com/fonts/docs/material_symbols#use_in_web + +### Modifying icons + +1. Update the list of icons to include in `scripts/material-symbols-update.mjs`. +2. Run `yarn run icons:update` in monorepo root. diff --git a/apps/scandic-web/README.md b/apps/scandic-web/README.md index ae6b0cc67..8981fca49 100644 --- a/apps/scandic-web/README.md +++ b/apps/scandic-web/README.md @@ -31,6 +31,10 @@ This will also spin up [Redis Insight ](https://redis.io/insight/) so that you c - Click **'Add Redis database'** - Provide Connection URL `redis://redis:6379` +### Icons / Material Symbols + +Read the README.md in the monorepo root. + ## Learn More To learn more about Next.js, take a look at the following resources: diff --git a/apps/scandic-web/app/[lang]/(live)/layout.tsx b/apps/scandic-web/app/[lang]/(live)/layout.tsx index 1c19a1052..a9cb480fa 100644 --- a/apps/scandic-web/app/[lang]/(live)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(live)/layout.tsx @@ -2,7 +2,6 @@ import "@scandic-hotels/design-system/fonts.css" import "@/app/globals.css" import "@/public/_static/css/design-system-new-deprecated.css" import "@scandic-hotels/design-system/style.css" -import "react-material-symbols/rounded" import { ReactQueryDevtools } from "@tanstack/react-query-devtools" import Script from "next/script" diff --git a/apps/scandic-web/app/[lang]/(live-current)/layout.tsx b/apps/scandic-web/app/[lang]/(live-current)/layout.tsx index b85a1bf7b..236b3611f 100644 --- a/apps/scandic-web/app/[lang]/(live-current)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(live-current)/layout.tsx @@ -2,7 +2,6 @@ import "@scandic-hotels/design-system/fonts.css" import "@/app/globals.css" import "@/public/_static/css/design-system-current-deprecated.css" import "@scandic-hotels/design-system/style.css" -import "react-material-symbols/rounded" import Script from "next/script" diff --git a/apps/scandic-web/app/[lang]/(partner)/layout.tsx b/apps/scandic-web/app/[lang]/(partner)/layout.tsx index 728b4b505..e06a3bdb2 100644 --- a/apps/scandic-web/app/[lang]/(partner)/layout.tsx +++ b/apps/scandic-web/app/[lang]/(partner)/layout.tsx @@ -2,7 +2,6 @@ import "@scandic-hotels/design-system/fonts.css" import "@/app/globals.css" import "@/public/_static/css/design-system-new-deprecated.css" import "@scandic-hotels/design-system/style.css" -import "react-material-symbols/rounded" import { ReactQueryDevtools } from "@tanstack/react-query-devtools" import Script from "next/script" diff --git a/apps/scandic-web/app/[lang]/webview/layout.tsx b/apps/scandic-web/app/[lang]/webview/layout.tsx index ccf5f938b..f65a6dc95 100644 --- a/apps/scandic-web/app/[lang]/webview/layout.tsx +++ b/apps/scandic-web/app/[lang]/webview/layout.tsx @@ -2,7 +2,6 @@ import "@scandic-hotels/design-system/fonts.css" import "@/app/globals.css" import "@/public/_static/css/design-system-new-deprecated.css" import "@scandic-hotels/design-system/style.css" -import "react-material-symbols/rounded" import Script from "next/script" diff --git a/apps/scandic-web/public/_static/fonts/material-symbols/rounded-eaec15a9.woff2 b/apps/scandic-web/public/_static/fonts/material-symbols/rounded-eaec15a9.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1abb94dce101edb02a129c35a8fd44c8be5661e3 GIT binary patch literal 25132 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 literal 0 HcmV?d00001 diff --git a/package.json b/package.json index 365916d33..f7a8dcbd8 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "dev:web": "turbo run dev --filter=@scandic-hotels/scandic-web --output-logs new-only", "dev:ds": "turbo run dev --filter=@scandic-hotels/design-system --output-logs new-only", "test": "turbo run test", - "postinstall": "husky" + "postinstall": "husky", + "icons:update": "node scripts/material-symbols-update.mjs" }, "workspaces": [ "apps/*", diff --git a/packages/design-system/README.md b/packages/design-system/README.md index 11cb36166..5b018c82d 100644 --- a/packages/design-system/README.md +++ b/packages/design-system/README.md @@ -148,6 +148,6 @@ Each component should have at least one Storybook story. A default story that sh Stories that involve other non-related components are compositions. These should be placed in the `Compositions/` folder where the composition has the best chance of discoverability, typically inside the component folder of the outermost component of the composition. Exporting the same composition in multiple places can be good for discoverability. -### Icons +### Icons / Material Symbols -Still a work in progress. +Read the README.md in the monorepo root. diff --git a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx index 72c937272..265d98c17 100644 --- a/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx +++ b/packages/design-system/lib/components/Icons/MaterialIcon/MaterialIcon.tsx @@ -8,29 +8,17 @@ import { iconVariants } from '../variants' import type { VariantProps } from 'class-variance-authority' export interface MaterialIconProps - extends Omit, + extends Pick, VariantProps { isFilled?: boolean } - export type MaterialIconSetIconProps = Omit - export function MaterialIcon({ - icon, color, - size = 24, - isFilled = false, className, + isFilled = false, ...props }: MaterialIconProps) { const classNames = iconVariants({ className, color }) - return ( - - ) + return } diff --git a/packages/design-system/lib/fonts.css b/packages/design-system/lib/fonts.css index 7ccb54037..fb73439bd 100644 --- a/packages/design-system/lib/fonts.css +++ b/packages/design-system/lib/fonts.css @@ -263,3 +263,32 @@ src: url(/_static/fonts/canela-deck/CanelaDeck-ThinItalic.otf) format('opentype'); } + +@font-face { + font-family: 'Material Symbols Rounded'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url(/_static/fonts/material-symbols/rounded-eaec15a9.woff2) + format('woff2'); +} + +.material-symbols { + font-family: 'Material Symbols Rounded'; + font-weight: normal; + font-style: normal; + font-size: inherit; + line-height: 1; + letter-spacing: normal; + text-transform: none; + display: inline-block; + white-space: nowrap; + word-wrap: normal; + direction: ltr; + user-select: none; + font-feature-settings: 'liga'; + -webkit-font-feature-settings: 'liga'; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + -moz-osx-font-smoothing: grayscale; +} diff --git a/packages/design-system/public/_static/fonts/material-symbols/rounded-eaec15a9.woff2 b/packages/design-system/public/_static/fonts/material-symbols/rounded-eaec15a9.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..1abb94dce101edb02a129c35a8fd44c8be5661e3 GIT binary patch literal 25132 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 literal 0 HcmV?d00001 diff --git a/scripts/material-symbols-update.mjs b/scripts/material-symbols-update.mjs new file mode 100644 index 000000000..72ce3d0de --- /dev/null +++ b/scripts/material-symbols-update.mjs @@ -0,0 +1,277 @@ +// @ts-check +import crypto from 'node:crypto'; +import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import { createWriteStream } from 'node:fs'; +import { resolve, join } from 'node:path'; +import { Readable } from 'node:stream'; +import { pipeline } from 'node:stream/promises'; + +import stringify from 'json-stable-stringify-without-jsonify'; + +// Defines where the font lives +const DESIGN_SYSTEM_FONT_DIR = `./packages/design-system/public/_static/fonts/material-symbols`; +const WEB_FONT_DIR = `./apps/scandic-web/public/_static/fonts/material-symbols`; + +// Defines the settings for the font +const FONT_BASE_URL = `https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,400,0..1,0`; + +// Defines the subset of icons for the font +const icons = [ + 'accessibility', + 'accessible', + 'add', + 'add_circle', + 'air', + 'air_purifier_gen', + 'apparel', + 'arrow_back', + 'arrow_forward', + 'arrow_right', + 'arrow_upward', + 'asterisk', + 'bakery_dining', + 'beach_access', + 'bed', + 'business_center', + 'calendar_add_on', + 'calendar_month', + 'calendar_today', + 'call', + 'call_quality', + 'camera', + 'cancel', + 'chair', + 'check', + 'check_box', + 'check_circle', + 'checkroom', + 'chevron_left', + 'chevron_right', + 'close', + 'coffee', + 'compare_arrows', + 'concierge', + 'connected_tv', + 'content_copy', + 'contract', + 'countertops', + 'credit_card', + 'credit_card_heart', + 'deck', + 'delete', + 'desk', + 'device_thermostat', + 'diamond', + 'dining', + 'directions', + 'downhill_skiing', + 'download', + 'dresser', + 'edit', + 'edit_square', + 'electric_bike', + 'electric_car', + 'elevator', + 'emoji_transportation', + 'error', + 'error_circle_rounded', + 'exercise', + 'family_restroom', + 'fastfood', + 'favorite', + 'fax', + 'featured_seasonal_and_gifts', + 'filter', + 'filter_alt', + 'floor_lamp', + 'garage', + 'globe', + 'groups', + 'health_and_beauty', + 'heat', + 'hiking', + 'home', + 'hot_tub', + 'imagesmode', + 'info', + 'iron', + 'kayaking', + 'kettle', + 'keyboard_arrow_down', + 'keyboard_arrow_up', + 'laundry', + 'link', + 'liquor', + 'local_bar', + 'local_cafe', + 'local_convenience_store', + 'local_laundry_service', + 'local_parking', + 'location_city', + 'location_on', + 'lock', + 'luggage', + 'mail', + 'map', + 'meeting_room', + 'mode_fan', + 'museum', + 'nature', + 'nightlife', + 'open_in_new', + 'pan_zoom', + 'pedal_bike', + 'person', + 'pets', + 'phone', + 'pool', + 'refresh', + 'remove', + 'restaurant', + 'room_service', + 'sauna', + 'search', + 'sell', + 'shopping_bag', + 'skateboarding', + 'smoke_free', + 'smoking_rooms', + 'spa', + 'sports_esports', + 'sports_golf', + 'sports_tennis', + 'star', + 'straighten', + 'styler', + 'swipe', + 'sync_saved_locally', + 'theater_comedy', + 'train', + 'travel', + 'tv_remote', + 'upload', + 'visibility', + 'visibility_off', + 'warning', + 'water_full', + 'wifi', +]; + +function createHash(value) { + const stringified = stringify(value); + const hash = crypto.createHash('sha256'); + hash.update(stringified); + return hash.digest('hex'); +} + +const hash = createHash(icons).substring(0, 8); + +async function fetchIconUrl(url) { + const response = await fetch(url, { + headers: { + Accept: + 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'User-Agent': + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36', + }, + }); + + if (!response.ok) { + console.error(`Unable to fetch woff2 for ${url}`); + process.exit(1); + } + + const text = await response.text(); + + const isWoff2 = /format\('woff2'\)/.test(text); + if (!isWoff2) { + console.error(`Unable to identify woff2 font in response`); + process.exit(1); + } + + const srcUrl = text.match(/src: url\(([^)]+)\)/); + + if (srcUrl && srcUrl[1]) { + return srcUrl[1]; + } + + return null; +} + +async function download(url, destFolder) { + const dest = resolve(join(destFolder, `/rounded-${hash}.woff2`)); + + try { + const response = await fetch(url); + + if (!response.ok) { + console.error(`Unable to fetch ${url}`); + process.exit(1); + } + + if (!response.body) { + console.error(`Bad response from ${url}`); + process.exit(1); + } + + const fileStream = createWriteStream(dest); + + // @ts-expect-error: type mismatch + const readableNodeStream = Readable.fromWeb(response.body); + + await pipeline(readableNodeStream, fileStream); + } catch (error) { + console.error(`Error downloading file from ${url}:`, error); + process.exit(1); + } +} +async function cleanFontDirs(folderPath) { + await rm(DESIGN_SYSTEM_FONT_DIR, { recursive: true, force: true }); + await mkdir(DESIGN_SYSTEM_FONT_DIR, { recursive: true }); + + await rm(WEB_FONT_DIR, { recursive: true, force: true }); + await mkdir(WEB_FONT_DIR, { recursive: true }); +} + +async function updateFontCSS() { + const file = './packages/design-system/lib/fonts.css'; + + const css = await readFile(file, { + encoding: 'utf-8', + }); + + await writeFile( + file, + css.replace( + /url\(\/_static\/fonts\/material-symbols\/rounded[^)]+\)/, + `url(/_static/fonts/material-symbols/rounded-${hash}.woff2)` + ), + { + encoding: 'utf-8', + } + ); +} + +async function main() { + const fontUrl = `${FONT_BASE_URL}&icon_names=${icons.join(',')}&display=block`; + + const iconUrl = await fetchIconUrl(fontUrl); + + if (iconUrl) { + await cleanFontDirs(); + + await download(iconUrl, DESIGN_SYSTEM_FONT_DIR); + await download(iconUrl, WEB_FONT_DIR); + + await updateFontCSS(); + + console.log('Successfully updated icons!'); + process.exit(0); + } else { + console.error( + `Unable to find the icon font src URL in CSS response from Google Fonts at ${fontUrl}` + ); + } +} + +main();