fix(SW-2753): change chevron in top navigation header * fix(SW-2753): change chevron in top navigation header Approved-by: Anton Gunnarsson
339 lines
6.7 KiB
JavaScript
339 lines
6.7 KiB
JavaScript
// @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',
|
|
'airline_seat_recline_normal',
|
|
'airplane_ticket',
|
|
'apartment',
|
|
'apparel',
|
|
'arrow_back',
|
|
'arrow_forward_ios',
|
|
'arrow_forward',
|
|
'arrow_right',
|
|
'arrow_upward',
|
|
'assistant_navigation',
|
|
'asterisk',
|
|
'attractions',
|
|
'award_star',
|
|
'bakery_dining',
|
|
'balcony',
|
|
'bathroom',
|
|
'bathtub',
|
|
'beach_access',
|
|
'bed',
|
|
'bedroom_parent',
|
|
'box',
|
|
'business_center',
|
|
'calendar_add_on',
|
|
'calendar_clock',
|
|
'calendar_month',
|
|
'calendar_today',
|
|
'call',
|
|
'call_quality',
|
|
'camera',
|
|
'cancel',
|
|
'chair',
|
|
'charging_station',
|
|
'check',
|
|
'check_box',
|
|
'check_circle',
|
|
'checked_bag',
|
|
'checkroom',
|
|
'chevron_left',
|
|
'chevron_right',
|
|
'close',
|
|
'coffee',
|
|
'coffee_maker',
|
|
'compare_arrows',
|
|
'computer',
|
|
'concierge',
|
|
'confirmation_number',
|
|
'connected_tv',
|
|
'content_copy',
|
|
'contract',
|
|
'cool_to_dry',
|
|
'countertops',
|
|
'credit_card',
|
|
'credit_card_heart',
|
|
'curtains',
|
|
'curtains_closed',
|
|
'deck',
|
|
'delete',
|
|
'desk',
|
|
'device_thermostat',
|
|
'diamond',
|
|
'dining',
|
|
'directions',
|
|
'directions_run',
|
|
'directions_subway',
|
|
'downhill_skiing',
|
|
'download',
|
|
'dresser',
|
|
'edit',
|
|
'edit_calendar',
|
|
'edit_square',
|
|
'electric_bike',
|
|
'electric_car',
|
|
'elevator',
|
|
'emoji_transportation',
|
|
'error',
|
|
'error_circle_rounded',
|
|
'exercise',
|
|
'family_restroom',
|
|
'fastfood',
|
|
'favorite',
|
|
'fax',
|
|
'featured_seasonal_and_gifts',
|
|
'festival',
|
|
'filter',
|
|
'filter_alt',
|
|
'floor_lamp',
|
|
'forest',
|
|
'garage',
|
|
'globe',
|
|
'golf_course',
|
|
'groups',
|
|
'health_and_beauty',
|
|
'heat',
|
|
'hiking',
|
|
'home',
|
|
'hot_tub',
|
|
'houseboat',
|
|
'hvac',
|
|
'id_card',
|
|
'imagesmode',
|
|
'info',
|
|
'iron',
|
|
'kayaking',
|
|
'kettle',
|
|
'keyboard_arrow_down',
|
|
'keyboard_arrow_up',
|
|
'king_bed',
|
|
'kitchen',
|
|
'landscape',
|
|
'laundry',
|
|
'link',
|
|
'liquor',
|
|
'live_tv',
|
|
'local_bar',
|
|
'local_cafe',
|
|
'local_convenience_store',
|
|
'local_drink',
|
|
'local_laundry_service',
|
|
'local_parking',
|
|
'location_city',
|
|
'location_on',
|
|
'lock',
|
|
'loyalty',
|
|
'luggage',
|
|
'mail',
|
|
'map',
|
|
'meeting_room',
|
|
'microwave',
|
|
'mode_fan',
|
|
'museum',
|
|
'music_cast',
|
|
'music_note',
|
|
'nature',
|
|
'night_shelter',
|
|
'nightlife',
|
|
'open_in_new',
|
|
'pan_zoom',
|
|
'panorama',
|
|
'pedal_bike',
|
|
'person',
|
|
'pets',
|
|
'phone',
|
|
'pool',
|
|
'print',
|
|
'radio',
|
|
'recommend',
|
|
'redeem',
|
|
'refresh',
|
|
'remove',
|
|
'restaurant',
|
|
'room_service',
|
|
'router',
|
|
'sailing',
|
|
'sauna',
|
|
'scene',
|
|
'search',
|
|
'sell',
|
|
'shopping_bag',
|
|
'shower',
|
|
'single_bed',
|
|
'skateboarding',
|
|
'smoke_free',
|
|
'smoking_rooms',
|
|
'spa',
|
|
'sports_esports',
|
|
'sports_golf',
|
|
'sports_handball',
|
|
'sports_tennis',
|
|
'stairs',
|
|
'star',
|
|
'straighten',
|
|
'styler',
|
|
'support_agent',
|
|
'swipe',
|
|
'sync_saved_locally',
|
|
'table_bar',
|
|
'theater_comedy',
|
|
'things_to_do',
|
|
'train',
|
|
'tram',
|
|
'transit_ticket',
|
|
'travel',
|
|
'travel_luggage_and_bags',
|
|
'tv_guide',
|
|
'tv_remote',
|
|
'upload',
|
|
'visibility',
|
|
'visibility_off',
|
|
'ward',
|
|
'warning',
|
|
'water_full',
|
|
'wifi',
|
|
'yard',
|
|
].sort();
|
|
|
|
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();
|