mirror of
https://github.com/cberane/obsidian-material-symbols.git
synced 2026-07-22 07:20:26 +00:00
feat: update Material Symbols font and add automation scripts
- Updated Material Symbols to latest version with complete icon set - Added `update-font.mjs` script for automated future font updates - Added `deploy.mjs` script with proper error handling - Fixed potential null pointer in font update logic - Bumped version and restored repository URL
This commit is contained in:
parent
78f795c5ed
commit
75c6e4ea55
6 changed files with 177 additions and 6 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -21,3 +21,6 @@ data.json
|
|||
# Exclude macOS Finder (System Explorer) View States
|
||||
.DS_Store
|
||||
/package-lock.json
|
||||
|
||||
# Deploy directory
|
||||
deploy/
|
||||
|
|
|
|||
42
deploy.mjs
Normal file
42
deploy.mjs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env node
|
||||
import { execSync } from 'child_process';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const deployDir = path.join(__dirname, 'deploy');
|
||||
const files = ['manifest.json', 'main.js', 'styles.css'];
|
||||
|
||||
// 1. Ensure deploy/ exists (create or reuse)
|
||||
fs.mkdirSync(deployDir, { recursive: true });
|
||||
|
||||
// 2. Install dependencies
|
||||
console.log('Installing dependencies...');
|
||||
execSync('npm install', { stdio: 'inherit', cwd: __dirname });
|
||||
|
||||
// 3. Update Material Symbols font
|
||||
console.log('\nUpdating Material Symbols font...');
|
||||
execSync('node update-font.mjs', { stdio: 'inherit', cwd: __dirname });
|
||||
|
||||
// 4. Run the production build
|
||||
console.log('\nRunning npm run build...');
|
||||
execSync('npm run build', { stdio: 'inherit', cwd: __dirname });
|
||||
|
||||
// 5. Copy deployment files
|
||||
console.log('\nCopying files to deploy/...');
|
||||
for (const file of files) {
|
||||
const srcPath = path.join(__dirname, file);
|
||||
const destPath = path.join(deployDir, file);
|
||||
|
||||
if (!fs.existsSync(srcPath)) {
|
||||
console.error(`Error: Expected source file not found: ${srcPath}`);
|
||||
console.error('Deployment aborted. Ensure the build has produced all required files.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
fs.copyFileSync(srcPath, destPath);
|
||||
console.log(`Copied ${file} → deploy/${file}`);
|
||||
}
|
||||
|
||||
console.log('\n✓ Full deployment complete. Files are in deploy/');
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"id": "material-symbols",
|
||||
"name": "Material Symbols",
|
||||
"version": "0.1.0",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "This plugin adds the material symbols (outlined) to obsidian",
|
||||
"author": "Cristoph Berane",
|
||||
"authorUrl": "https://www.berane-it.de",
|
||||
"authorUrl": "https://github.com/cberane/obsidian-material-symbols",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
125
update-font.mjs
Executable file
125
update-font.mjs
Executable file
|
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import https from 'https';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// Fetch URL with a modern User-Agent to get woff2 format
|
||||
function fetchUrl(url, userAgent = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
headers: userAgent ? { 'User-Agent': userAgent } : {},
|
||||
};
|
||||
|
||||
https.get(url, options, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(data);
|
||||
} else {
|
||||
reject(new Error(`HTTP ${res.statusCode}: ${url}`));
|
||||
}
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch binary data (for woff2 font file)
|
||||
function fetchBinary(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
https.get(url, (res) => {
|
||||
const chunks = [];
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(Buffer.concat(chunks));
|
||||
} else {
|
||||
reject(new Error(`HTTP ${res.statusCode}: ${url}`));
|
||||
}
|
||||
});
|
||||
}).on('error', reject);
|
||||
});
|
||||
}
|
||||
|
||||
// Extract woff2 URL from CSS
|
||||
function extractWoff2Url(css) {
|
||||
// Match url() declarations in @font-face blocks
|
||||
const match = css.match(/url\((https:\/\/fonts\.gstatic\.com\/[^)]+\.woff2)\)/g);
|
||||
if (!match || match.length === 0) {
|
||||
throw new Error('No woff2 URL found in Google Fonts CSS');
|
||||
}
|
||||
|
||||
// Take the last one (largest/most complete subset) or any - for variable icon font they're all the same
|
||||
const lastMatch = match[match.length - 1];
|
||||
const urlMatch = lastMatch.match(/url\((https:\/\/fonts\.gstatic\.com\/[^)]+\.woff2)\)/);
|
||||
if (!urlMatch || urlMatch.length < 2) {
|
||||
throw new Error('No woff2 URL found in Google Fonts CSS');
|
||||
}
|
||||
return urlMatch[1];
|
||||
}
|
||||
|
||||
// Main update function
|
||||
async function updateFont() {
|
||||
try {
|
||||
console.log('Fetching Google Fonts CSS for Material Symbols Outlined...');
|
||||
|
||||
// Step 1: Fetch the Google Fonts CSS with modern User-Agent
|
||||
const css = await fetchUrl(
|
||||
'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
|
||||
);
|
||||
|
||||
// Step 2: Parse the woff2 URL
|
||||
const woff2Url = extractWoff2Url(css);
|
||||
console.log(`Found woff2 URL: ${woff2Url}`);
|
||||
|
||||
// Step 3: Download the woff2 font binary
|
||||
console.log('Downloading woff2 font...');
|
||||
const fontBinary = await fetchBinary(woff2Url);
|
||||
console.log(`Downloaded ${fontBinary.length} bytes`);
|
||||
|
||||
// Step 4: Base64-encode the binary
|
||||
const base64 = fontBinary.toString('base64');
|
||||
console.log(`Base64 encoded: ${base64.length} characters`);
|
||||
|
||||
// Step 5: Replace the src in styles.css
|
||||
const stylesPath = path.join(__dirname, 'styles.css');
|
||||
console.log(`Reading ${stylesPath}...`);
|
||||
|
||||
let stylesContent = fs.readFileSync(stylesPath, 'utf-8');
|
||||
|
||||
// Replace the src declaration inside @font-face
|
||||
// Target: src: url(data:application/octet-stream;base64,...) or variations with format()
|
||||
const srcRegex = /src:\s*url\(data:(?:font\/woff2;base64|application\/octet-stream;base64),[^)]+\)(?:\s*format\([^)]*\))?[^;]*;/;
|
||||
|
||||
if (!srcRegex.test(stylesContent)) {
|
||||
throw new Error('Could not find src declaration in styles.css');
|
||||
}
|
||||
|
||||
const newSrc = `src: url(data:application/octet-stream;base64,${base64}) format('woff2');`;
|
||||
stylesContent = stylesContent.replace(srcRegex, newSrc);
|
||||
|
||||
console.log('Writing updated styles.css...');
|
||||
fs.writeFileSync(stylesPath, stylesContent, 'utf-8');
|
||||
|
||||
console.log('✓ Font update completed successfully!');
|
||||
console.log(`✓ Updated base64 size: ${base64.length} characters (original ~3MB woff2 file)`);
|
||||
} catch (error) {
|
||||
console.error('✗ Error updating font:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
updateFont();
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
{
|
||||
"0.1.0": "0.15.0"
|
||||
}
|
||||
"0.1.0": "0.15.0",
|
||||
"1.0.0": "0.15.0"
|
||||
}
|
||||
Loading…
Reference in a new issue