mirror of
https://github.com/bitwarden/browser
synced 2026-02-11 14:04:03 +00:00
font WIP
This commit is contained in:
269
scripts/material-icons/NEXT-STEPS.md
Normal file
269
scripts/material-icons/NEXT-STEPS.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# Material Icons Migration - Next Steps
|
||||
|
||||
## ✅ What's Been Completed
|
||||
|
||||
1. ✅ **Installed Material Icons package** - `@material-design-icons/svg` v0.14.15
|
||||
2. ✅ **Created icon mapping** - 95 BWI icons mapped to Material Icons equivalents
|
||||
3. ✅ **Extracted SVG files** - All 95 icons successfully extracted and renamed
|
||||
4. ✅ **NPM scripts added** - Convenient commands for future updates
|
||||
|
||||
## 📦 What You Have Now
|
||||
|
||||
- **95 SVG files** in `.material-icons-staging/` directory
|
||||
- Each file is named with BWI convention (e.g., `bwi-close.svg`, `bwi-lock.svg`)
|
||||
- Files are ready to be converted into a font
|
||||
|
||||
## 🎯 Next Steps (Manual - You Need to Do This)
|
||||
|
||||
### Step 1: Generate Icon Font
|
||||
|
||||
You need to convert the 95 SVG files into a font file. Choose one option:
|
||||
|
||||
#### **Option A: IcoMoon (Recommended - Web-based, Free)**
|
||||
|
||||
1. Open https://icomoon.io/app in your browser
|
||||
2. Click **"Import Icons"** button (top left)
|
||||
3. Select **all 95 SVG files** from:
|
||||
```
|
||||
/Users/bryancunningham/Desktop/Code/clients/.material-icons-staging/
|
||||
```
|
||||
4. After import, click **"Select All"** to select all imported icons
|
||||
5. Click **"Generate Font"** button (bottom right)
|
||||
6. Click ⚙️ icon for preferences:
|
||||
- **Font Name:** `bwi-font`
|
||||
- **Class Prefix:** `bwi-`
|
||||
- Leave other settings as default
|
||||
7. Click **"Download"** button
|
||||
8. Extract the downloaded ZIP file
|
||||
|
||||
#### **Option B: Fantasticon (Command-line, Automated)**
|
||||
|
||||
```bash
|
||||
# Install fantasticon globally
|
||||
npm install -g fantasticon
|
||||
|
||||
# Generate font (run from project root)
|
||||
fantasticon .material-icons-staging \
|
||||
--output-dir libs/angular/src/scss/bwicons/fonts \
|
||||
--font-types woff2,woff,ttf,svg \
|
||||
--name bwi-font \
|
||||
--prefix bwi- \
|
||||
--normalize
|
||||
|
||||
# Skip to Step 3 (Testing)
|
||||
```
|
||||
|
||||
### Step 2: Replace Font Files
|
||||
|
||||
After generating the font (via IcoMoon or Fantasticon):
|
||||
|
||||
1. **Backup current font files** (optional but recommended):
|
||||
|
||||
```bash
|
||||
cp -r libs/angular/src/scss/bwicons/fonts libs/angular/src/scss/bwicons/fonts.backup
|
||||
```
|
||||
|
||||
2. **Copy new font files** from the downloaded package to:
|
||||
|
||||
```
|
||||
libs/angular/src/scss/bwicons/fonts/
|
||||
```
|
||||
|
||||
You need these 4 files:
|
||||
- `bwi-font.svg`
|
||||
- `bwi-font.ttf`
|
||||
- `bwi-font.woff`
|
||||
- `bwi-font.woff2`
|
||||
|
||||
3. **Verify files are in place**:
|
||||
```bash
|
||||
ls -lh libs/angular/src/scss/bwicons/fonts/
|
||||
```
|
||||
|
||||
### Step 3: Test the Changes
|
||||
|
||||
1. **Build the project**:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
2. **Start development server**:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
3. **Visual inspection**:
|
||||
- Open the app in your browser
|
||||
- Check various pages with icons
|
||||
- Verify icons display correctly
|
||||
- Test icon buttons (click, hover states)
|
||||
|
||||
4. **Test in Storybook**:
|
||||
|
||||
```bash
|
||||
npm run storybook
|
||||
```
|
||||
|
||||
- Navigate to Component Library → Icon
|
||||
- Check that all icons render properly
|
||||
|
||||
5. **Test across all apps**:
|
||||
- **Web app** - Main application
|
||||
- **Browser extension** - All popup pages
|
||||
- **Desktop app** - All windows
|
||||
|
||||
### Step 4: Commit the Changes
|
||||
|
||||
Once everything looks good:
|
||||
|
||||
```bash
|
||||
# Stage the new font files
|
||||
git add libs/angular/src/scss/bwicons/fonts/
|
||||
|
||||
# Stage the mapping and scripts
|
||||
git add scripts/material-icons/
|
||||
git add package.json
|
||||
|
||||
# Commit
|
||||
git commit -m "Replace BWI font with Material Design icons
|
||||
|
||||
- Add Material Icons package (@material-design-icons/svg)
|
||||
- Create BWI → Material Icons mapping (95 icons)
|
||||
- Generate new BWI font using Material Design glyphs
|
||||
- All existing code continues to work (zero code changes)
|
||||
- Icons now follow Material Design guidelines
|
||||
|
||||
🤖 Generated with Claude Code"
|
||||
```
|
||||
|
||||
## 🔄 Rollback Instructions
|
||||
|
||||
If anything goes wrong, you can instantly rollback:
|
||||
|
||||
```bash
|
||||
# Restore original font files
|
||||
git checkout HEAD -- libs/angular/src/scss/bwicons/fonts/
|
||||
|
||||
# Rebuild
|
||||
npm run build
|
||||
```
|
||||
|
||||
## 📝 Icon Mappings Reference
|
||||
|
||||
Here are some notable mappings from your Figma design:
|
||||
|
||||
### Status Indicators
|
||||
|
||||
- `bwi-check` → `check`
|
||||
- `bwi-error` → `error`
|
||||
- `bwi-info-circle` → `info`
|
||||
- `bwi-spinner` → `sync`
|
||||
- `bwi-exclamation-triangle` → `warning`
|
||||
|
||||
### Common Actions
|
||||
|
||||
- `bwi-plus` → `add`
|
||||
- `bwi-pencil` → `edit`
|
||||
- `bwi-trash` → `delete`
|
||||
- `bwi-close` → `close`
|
||||
- `bwi-search` → `search`
|
||||
|
||||
### Bitwarden Objects
|
||||
|
||||
- `bwi-vault` → `inventory_2`
|
||||
- `bwi-lock` → `lock`
|
||||
- `bwi-key` → `vpn_key`
|
||||
- `bwi-folder` → `folder`
|
||||
- `bwi-collection` → `folder_shared`
|
||||
|
||||
### Navigation
|
||||
|
||||
- `bwi-angle-down` → `keyboard_arrow_down`
|
||||
- `bwi-angle-up` → `keyboard_arrow_up`
|
||||
- `bwi-ellipsis-h` → `more_horiz`
|
||||
- `bwi-ellipsis-v` → `more_vert`
|
||||
|
||||
**Full mapping:** See [scripts/material-icons/icon-mapping.ts](./icon-mapping.ts)
|
||||
|
||||
## 🎯 What This Achieves
|
||||
|
||||
✅ **Zero code changes** - All 1000+ usages of `bwi-*` classes continue to work
|
||||
✅ **Material Design** - Modern, consistent icon design
|
||||
✅ **Easy rollback** - Just revert 4 font files if needed
|
||||
✅ **Future-proof** - Can easily update icons by regenerating font
|
||||
✅ **No breaking changes** - Fully backward compatible
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- **Mapping configuration:** [scripts/material-icons/icon-mapping.ts](./icon-mapping.ts)
|
||||
- **Extraction script:** [scripts/material-icons/extract-material-svgs.ts](./extract-material-svgs.ts)
|
||||
- **Full README:** [scripts/material-icons/README.md](./README.md)
|
||||
- **Extracted files:** `.material-icons-staging/` (95 SVG files)
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Icons not displaying after font replacement
|
||||
|
||||
**Issue:** Icons show as squares or don't render
|
||||
|
||||
**Solution:**
|
||||
|
||||
1. Clear browser cache (Cmd+Shift+R / Ctrl+Shift+R)
|
||||
2. Verify font files are correct:
|
||||
```bash
|
||||
ls -lh libs/angular/src/scss/bwicons/fonts/
|
||||
```
|
||||
3. Check browser console for font loading errors
|
||||
4. Rebuild project: `npm run build`
|
||||
|
||||
### Font generation warnings in IcoMoon
|
||||
|
||||
**Issue:** IcoMoon shows warnings about icon complexity
|
||||
|
||||
**Solution:**
|
||||
|
||||
- Click "Ignore" or "Simplify" - Material Icons are optimized
|
||||
- Warnings are usually safe to ignore for outline icons
|
||||
|
||||
### Icons have wrong size/alignment
|
||||
|
||||
**Issue:** Icons appear too large/small or misaligned
|
||||
|
||||
**Solution:**
|
||||
|
||||
- Regenerate font with "Normalize" option enabled in IcoMoon
|
||||
- Or use Fantasticon with `--normalize` flag
|
||||
|
||||
## 📞 Need Help?
|
||||
|
||||
- **Material Icons Gallery:** https://fonts.google.com/icons
|
||||
- **IcoMoon Documentation:** https://icomoon.io/docs.html
|
||||
- **Figma Design File:** https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library
|
||||
|
||||
## ⚡ Quick Commands Reference
|
||||
|
||||
```bash
|
||||
# Reinstall Material Icons (if needed)
|
||||
npm run icons:install
|
||||
|
||||
# Re-extract SVG files (if mapping changes)
|
||||
npm run icons:extract
|
||||
|
||||
# Complete setup from scratch
|
||||
npm run icons:setup
|
||||
|
||||
# Build project
|
||||
npm run build
|
||||
|
||||
# Run Storybook
|
||||
npm run storybook
|
||||
|
||||
# Rollback font files
|
||||
git checkout HEAD -- libs/angular/src/scss/bwicons/fonts/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Ready to proceed?** Follow Step 1 above to generate your font! 🚀
|
||||
277
scripts/material-icons/README.md
Normal file
277
scripts/material-icons/README.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Material Icons Migration - Zero Code Changes
|
||||
|
||||
This directory contains scripts and configuration for migrating Bitwarden's BWI icon font to use Material Design icon glyphs while maintaining 100% backward compatibility.
|
||||
|
||||
## Overview
|
||||
|
||||
**Goal:** Replace all BWI icon glyphs with Material Design equivalents **without changing any code**.
|
||||
|
||||
**Result:** All existing code using `bwi-close`, `bwi-lock`, etc. will continue to work exactly the same, but will render Material Design icons instead.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Step 1: Install Material Icons package
|
||||
npm run icons:install
|
||||
|
||||
# Step 2: Extract and prepare SVG files
|
||||
npm run icons:extract
|
||||
|
||||
# Step 3: Generate new font (see instructions below)
|
||||
|
||||
# Step 4: Replace font files and test
|
||||
```
|
||||
|
||||
## Detailed Steps
|
||||
|
||||
### Step 1: Install Material Icons
|
||||
|
||||
```bash
|
||||
npm run icons:install
|
||||
```
|
||||
|
||||
This installs `@material-design-icons/svg` package which contains all Material Design icons as individual SVG files.
|
||||
|
||||
### Step 2: Extract Icon SVGs
|
||||
|
||||
```bash
|
||||
npm run icons:extract
|
||||
```
|
||||
|
||||
This script:
|
||||
|
||||
- Reads the icon mapping from [`icon-mapping.ts`](./icon-mapping.ts)
|
||||
- Finds each Material Icon SVG file (outlined variant)
|
||||
- Renames them to match BWI names (e.g., `close.svg` → `bwi-close.svg`)
|
||||
- Copies them to `.material-icons-staging/` directory
|
||||
|
||||
**Output:**
|
||||
|
||||
- `.material-icons-staging/` - Contains 80+ renamed SVG files
|
||||
- `.material-icons-staging/extraction-report.json` - Details about what was extracted
|
||||
- `.material-icons-staging/INSTRUCTIONS.md` - Next steps
|
||||
|
||||
### Step 3: Generate Icon Font
|
||||
|
||||
Now you need to convert the SVG files into a font. You have three options:
|
||||
|
||||
#### Option A: IcoMoon (Recommended - Web-based)
|
||||
|
||||
1. Go to https://icomoon.io/app
|
||||
2. Click "Import Icons" button (top left)
|
||||
3. Select all SVG files from `.material-icons-staging/`
|
||||
4. Select all imported icons (click "Select All")
|
||||
5. Click "Generate Font" button (bottom right)
|
||||
6. In font preferences:
|
||||
- **Font Name:** `bwi-font`
|
||||
- **Class Prefix:** `bwi-`
|
||||
- Keep other settings as default
|
||||
7. Click "Download"
|
||||
8. Extract the downloaded ZIP file
|
||||
9. Copy these files from `fonts/` folder to `libs/angular/src/scss/bwicons/fonts/`:
|
||||
- `bwi-font.svg`
|
||||
- `bwi-font.ttf`
|
||||
- `bwi-font.woff`
|
||||
- `bwi-font.woff2`
|
||||
|
||||
#### Option B: Fontello (Web-based)
|
||||
|
||||
1. Go to https://fontello.com
|
||||
2. Drag and drop all SVG files from `.material-icons-staging/`
|
||||
3. Customize settings:
|
||||
- Font Name: `bwi-font`
|
||||
- CSS Prefix: `bwi-`
|
||||
4. Download font package
|
||||
5. Copy font files to `libs/angular/src/scss/bwicons/fonts/`
|
||||
|
||||
#### Option C: Fantasticon (Command-line)
|
||||
|
||||
```bash
|
||||
# Install fantasticon globally
|
||||
npm install -g fantasticon
|
||||
|
||||
# Generate font
|
||||
fantasticon .material-icons-staging \
|
||||
--output-dir libs/angular/src/scss/bwicons/fonts \
|
||||
--font-types woff2,woff,ttf,svg \
|
||||
--name bwi-font \
|
||||
--prefix bwi- \
|
||||
--normalize
|
||||
```
|
||||
|
||||
### Step 4: Test the Changes
|
||||
|
||||
After replacing the font files:
|
||||
|
||||
```bash
|
||||
# Build the project
|
||||
npm run build
|
||||
|
||||
# Start development server
|
||||
npm start
|
||||
|
||||
# Test in each app:
|
||||
# - Browser extension
|
||||
# - Desktop app
|
||||
# - Web app
|
||||
```
|
||||
|
||||
**What to test:**
|
||||
|
||||
- ✅ All icons render correctly
|
||||
- ✅ Icons maintain proper sizing
|
||||
- ✅ Icons work in all components (buttons, menus, lists, etc.)
|
||||
- ✅ No console errors
|
||||
- ✅ Icons work across all themes (light/dark)
|
||||
|
||||
### Step 5: Rollback (if needed)
|
||||
|
||||
If anything goes wrong, you can instantly rollback:
|
||||
|
||||
```bash
|
||||
git checkout HEAD -- libs/angular/src/scss/bwicons/fonts/
|
||||
```
|
||||
|
||||
This restores the original BWI font files.
|
||||
|
||||
## Icon Mapping
|
||||
|
||||
The complete mapping is defined in [`icon-mapping.ts`](./icon-mapping.ts):
|
||||
|
||||
```typescript
|
||||
export const BWI_TO_MATERIAL_MAPPING = {
|
||||
"bwi-close": "close",
|
||||
"bwi-lock": "lock",
|
||||
"bwi-unlock": "lock_open",
|
||||
"bwi-check": "check",
|
||||
// ... 80+ more mappings
|
||||
};
|
||||
```
|
||||
|
||||
### Icon Categories
|
||||
|
||||
1. **Status Indicators** - check, error, info, warning, etc.
|
||||
2. **Bitwarden Objects** - vault, collection, folder, credit-card, etc.
|
||||
3. **Actions** - add, edit, delete, download, share, etc.
|
||||
4. **Arrows & Menus** - angle-down, angle-up, ellipsis-h, etc.
|
||||
5. **Miscellaneous** - browser, desktop, mobile, key, etc.
|
||||
6. **3rd Party** - bitcoin, paypal, etc.
|
||||
|
||||
### New Icons
|
||||
|
||||
The mapping also identifies **new Material Icons** that don't have BWI equivalents:
|
||||
|
||||
- `autofill` - New icon for autofill feature
|
||||
- `clear` - Differentiated from error icon
|
||||
- `redo` - Paired with undo
|
||||
- `arrow-down`, `arrow-up`, `arrow-left`, `arrow-right` - Directional arrows
|
||||
- `diamond` - Premium plans indicator
|
||||
- `sso` - Single sign-on
|
||||
- And more...
|
||||
|
||||
These can be added to the component library separately.
|
||||
|
||||
## What Gets Changed?
|
||||
|
||||
### ✅ What Changes
|
||||
|
||||
- **Font files** in `libs/angular/src/scss/bwicons/fonts/`
|
||||
- **Visual appearance** of icons (now Material Design)
|
||||
|
||||
### ❌ What Stays The Same
|
||||
|
||||
- **All HTML/template files** - No changes needed
|
||||
- **All TypeScript files** - No changes needed
|
||||
- **All class names** - Still use `bwi-close`, `bwi-lock`, etc.
|
||||
- **All component code** - Works exactly as before
|
||||
- **Icon button usage** - Still `bitIconButton="bwi-close"`
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
scripts/material-icons/
|
||||
├── README.md # This file
|
||||
├── icon-mapping.ts # BWI → Material mappings (80+ icons)
|
||||
├── extract-material-svgs.ts # Extraction script
|
||||
└── .material-icons-staging/ # Generated during extraction
|
||||
├── bwi-close.svg
|
||||
├── bwi-lock.svg
|
||||
├── ... (80+ SVG files)
|
||||
├── extraction-report.json
|
||||
└── INSTRUCTIONS.md
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Problem: Material Icons package not found
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
npm run icons:install
|
||||
```
|
||||
|
||||
### Problem: Some icons missing after extraction
|
||||
|
||||
**Check:**
|
||||
|
||||
1. Look at `.material-icons-staging/extraction-report.json`
|
||||
2. Failed icons will be listed with reasons
|
||||
3. Most common issue: Material Icon name doesn't exist
|
||||
4. Fix the mapping in `icon-mapping.ts` and re-run extraction
|
||||
|
||||
### Problem: Icons not displaying after font replacement
|
||||
|
||||
**Check:**
|
||||
|
||||
1. Font files are in correct location: `libs/angular/src/scss/bwicons/fonts/`
|
||||
2. Font file names are correct: `bwi-font.svg`, `bwi-font.ttf`, etc.
|
||||
3. Clear browser cache and rebuild
|
||||
4. Check browser console for font loading errors
|
||||
|
||||
### Problem: Icons have wrong size/alignment
|
||||
|
||||
**Solution:**
|
||||
|
||||
- This usually happens if font generation settings were incorrect
|
||||
- Regenerate font with proper settings (see Step 3)
|
||||
- Ensure "Normalize" option is enabled in font generator
|
||||
|
||||
## Notes from Figma Design
|
||||
|
||||
The following icons have special notes from the design team:
|
||||
|
||||
- **bwi-collection-shared** - Should be removed, use `bwi-collection` instead
|
||||
- **bwi-down-solid / bwi-up-solid** - Replace with new arrow icons in tables
|
||||
- **bwi-provider** - Replace SSO usage with new `sso` icon
|
||||
- **bwi-filter** - Consider using more standard filter icon in browser extension
|
||||
- **bwi-brush** - Needs artwork update to palette icon
|
||||
|
||||
See `ICON_NOTES` in [`icon-mapping.ts`](./icon-mapping.ts) for complete list.
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Zero code changes** - All 1000+ icon usages continue to work
|
||||
✅ **Instant rollback** - Just revert 4 font files
|
||||
✅ **Material Design consistency** - Modern, recognizable icons
|
||||
✅ **No breaking changes** - Fully backward compatible
|
||||
✅ **Easy testing** - Deploy and test without code migration
|
||||
✅ **Future-proof** - Can gradually add new Material Icons
|
||||
|
||||
## Next Steps
|
||||
|
||||
After successfully replacing the font:
|
||||
|
||||
1. **Test thoroughly** across all apps and components
|
||||
2. **Get design team approval** on icon appearance
|
||||
3. **Consider new icons** - Add new Material Icons identified in mapping
|
||||
4. **Clean up** - Remove deprecated icons like `bwi-collection-shared`
|
||||
5. **Update documentation** - Note that BWI now uses Material Design glyphs
|
||||
|
||||
## Support
|
||||
|
||||
Questions? Check:
|
||||
|
||||
- [Material Icons Gallery](https://fonts.google.com/icons)
|
||||
- [Figma Design File](https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library)
|
||||
- [IcoMoon Documentation](https://icomoon.io/docs.html)
|
||||
227
scripts/material-icons/extract-material-svgs.ts
Normal file
227
scripts/material-icons/extract-material-svgs.ts
Normal file
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env ts-node
|
||||
|
||||
/**
|
||||
* Extract Material Icon SVG files based on BWI → Material mapping
|
||||
*
|
||||
* This script:
|
||||
* 1. Reads the icon mapping configuration
|
||||
* 2. Finds the corresponding Material Icon SVG files
|
||||
* 3. Copies them to a staging directory for font generation
|
||||
* 4. Renames them to match BWI icon names
|
||||
*/
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import { BWI_TO_MATERIAL_MAPPING } from "./icon-mapping";
|
||||
|
||||
// Configuration
|
||||
const MATERIAL_ICONS_SOURCE = path.join(__dirname, "../../node_modules/@material-design-icons/svg");
|
||||
const OUTPUT_DIR = path.join(__dirname, "../../.material-icons-staging");
|
||||
const ICON_VARIANT = "outlined"; // Options: filled, outlined, round, sharp, two-tone
|
||||
|
||||
interface ExtractionResult {
|
||||
bwiName: string;
|
||||
materialName: string;
|
||||
sourcePath: string;
|
||||
outputPath: string;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean and prepare output directory
|
||||
*/
|
||||
function prepareOutputDirectory(): void {
|
||||
if (fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.rmSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a single Material Icon SVG
|
||||
*/
|
||||
function extractIcon(bwiName: string, materialName: string): ExtractionResult {
|
||||
const result: ExtractionResult = {
|
||||
bwiName,
|
||||
materialName,
|
||||
sourcePath: "",
|
||||
outputPath: "",
|
||||
success: false,
|
||||
};
|
||||
|
||||
try {
|
||||
// Construct source path
|
||||
// Material Icons are organized as: svg/{variant}/{icon_name}.svg
|
||||
const sourcePath = path.join(MATERIAL_ICONS_SOURCE, ICON_VARIANT, `${materialName}.svg`);
|
||||
|
||||
result.sourcePath = sourcePath;
|
||||
|
||||
// Check if source file exists
|
||||
if (!fs.existsSync(sourcePath)) {
|
||||
result.error = `Source file not found: ${sourcePath}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read SVG content
|
||||
const svgContent = fs.readFileSync(sourcePath, "utf-8");
|
||||
|
||||
// Create output filename: bwi-{name}.svg
|
||||
// This preserves the BWI naming convention for font generation
|
||||
const outputFileName = `${bwiName}.svg`;
|
||||
const outputPath = path.join(OUTPUT_DIR, outputFileName);
|
||||
|
||||
result.outputPath = outputPath;
|
||||
|
||||
// Write to output directory
|
||||
fs.writeFileSync(outputPath, svgContent, "utf-8");
|
||||
|
||||
result.success = true;
|
||||
return result;
|
||||
} catch (error) {
|
||||
result.error = error.message;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all Material Icons based on mapping
|
||||
*/
|
||||
function extractAllIcons(): void {
|
||||
const results: ExtractionResult[] = [];
|
||||
const errors: ExtractionResult[] = [];
|
||||
|
||||
// Process each mapping
|
||||
for (const [bwiName, materialName] of Object.entries(BWI_TO_MATERIAL_MAPPING)) {
|
||||
const result = extractIcon(bwiName, materialName);
|
||||
results.push(result);
|
||||
|
||||
if (!result.success) {
|
||||
errors.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Save extraction report
|
||||
const reportPath = path.join(OUTPUT_DIR, "extraction-report.json");
|
||||
const report = {
|
||||
timestamp: new Date().toISOString(),
|
||||
variant: ICON_VARIANT,
|
||||
totalMapped: results.length,
|
||||
successful: results.filter((r) => r.success).length,
|
||||
failed: errors.length,
|
||||
results,
|
||||
};
|
||||
|
||||
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
||||
|
||||
// Create instructions file
|
||||
createInstructionsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create instructions for next steps
|
||||
*/
|
||||
function createInstructionsFile(): void {
|
||||
const instructions = `
|
||||
# Material Icons Extraction Complete
|
||||
|
||||
## What Was Done
|
||||
- Extracted ${Object.keys(BWI_TO_MATERIAL_MAPPING).length} Material Icons (${ICON_VARIANT} variant)
|
||||
- Renamed to match BWI icon names
|
||||
- Saved to: ${OUTPUT_DIR}
|
||||
|
||||
## Next Steps: Generate Icon Font
|
||||
|
||||
### Option 1: Using IcoMoon (Recommended)
|
||||
1. Go to https://icomoon.io/app
|
||||
2. Click "Import Icons" button
|
||||
3. Select all SVG files from: ${OUTPUT_DIR}
|
||||
4. Select all imported icons
|
||||
5. Click "Generate Font" at bottom
|
||||
6. In font preferences:
|
||||
- Font Name: bwi-font
|
||||
- Class Prefix: bwi-
|
||||
- Keep existing icon names (they already have bwi- prefix)
|
||||
7. Download the font package
|
||||
8. Extract and copy these files to libs/angular/src/scss/bwicons/fonts/:
|
||||
- bwi-font.svg
|
||||
- bwi-font.ttf
|
||||
- bwi-font.woff
|
||||
- bwi-font.woff2
|
||||
|
||||
### Option 2: Using Fontello
|
||||
1. Go to https://fontello.com
|
||||
2. Drag and drop all SVG files from ${OUTPUT_DIR}
|
||||
3. Assign each icon to its glyph code
|
||||
4. Download font package
|
||||
5. Copy font files to libs/angular/src/scss/bwicons/fonts/
|
||||
|
||||
### Option 3: Automated (Advanced)
|
||||
Use a tool like 'fantasticon' or 'icon-font-generator':
|
||||
|
||||
\`\`\`bash
|
||||
npm install -g fantasticon
|
||||
|
||||
fantasticon ${OUTPUT_DIR} \\
|
||||
--output-dir libs/angular/src/scss/bwicons/fonts \\
|
||||
--font-types woff2,woff,ttf,svg \\
|
||||
--name bwi-font \\
|
||||
--prefix bwi- \\
|
||||
--normalize
|
||||
\`\`\`
|
||||
|
||||
## Testing
|
||||
After replacing font files:
|
||||
1. Run: npm run build
|
||||
2. Start dev server: npm start
|
||||
3. Check that all icons display correctly
|
||||
4. Test across: browser extension, desktop app, web app
|
||||
|
||||
## Rollback
|
||||
If anything goes wrong:
|
||||
\`\`\`bash
|
||||
git checkout HEAD -- libs/angular/src/scss/bwicons/fonts/
|
||||
\`\`\`
|
||||
|
||||
## Current Font Files Location
|
||||
${path.join(__dirname, "../../libs/angular/src/scss/bwicons/fonts")}
|
||||
`;
|
||||
|
||||
const instructionsPath = path.join(OUTPUT_DIR, "INSTRUCTIONS.md");
|
||||
fs.writeFileSync(instructionsPath, instructions.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Material Icons package is installed
|
||||
*/
|
||||
function validateMaterialIconsPackage(): boolean {
|
||||
if (!fs.existsSync(MATERIAL_ICONS_SOURCE)) {
|
||||
throw new Error(
|
||||
`Material Icons package not found at ${MATERIAL_ICONS_SOURCE}. Install with: npm install @material-design-icons/svg`,
|
||||
);
|
||||
}
|
||||
|
||||
const variantPath = path.join(MATERIAL_ICONS_SOURCE, ICON_VARIANT);
|
||||
if (!fs.existsSync(variantPath)) {
|
||||
throw new Error(`Icon variant '${ICON_VARIANT}' not found at ${variantPath}`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution
|
||||
*/
|
||||
function main(): void {
|
||||
validateMaterialIconsPackage();
|
||||
prepareOutputDirectory();
|
||||
extractAllIcons();
|
||||
}
|
||||
|
||||
// Run if executed directly
|
||||
if (require.main === module) {
|
||||
main();
|
||||
}
|
||||
|
||||
export { extractIcon, extractAllIcons, prepareOutputDirectory };
|
||||
206
scripts/material-icons/icon-mapping.ts
Normal file
206
scripts/material-icons/icon-mapping.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* Mapping from BWI icon names to Material Icon names
|
||||
*
|
||||
* This mapping is used to generate a new BWI font file where each BWI icon name
|
||||
* maps to a Material Design icon glyph.
|
||||
*
|
||||
* Source: Figma design file - Icon mapping tables
|
||||
* https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library
|
||||
*
|
||||
* Last updated: 2025-12-04
|
||||
*/
|
||||
|
||||
export const BWI_TO_MATERIAL_MAPPING = {
|
||||
// ============================================
|
||||
// STATUS INDICATORS
|
||||
// ============================================
|
||||
"bwi-check": "check",
|
||||
"bwi-error": "error",
|
||||
"bwi-info-circle": "info", // Was: bwi-info-circle
|
||||
"bwi-spinner": "sync", // Was: bwi-spinner (loading/spinner icon)
|
||||
"bwi-question-circle": "help", // Was: bwi-question-circle
|
||||
"bwi-exclamation-triangle": "warning", // Was: bwi-exclamation-triangle
|
||||
|
||||
// ============================================
|
||||
// BITWARDEN OBJECTS
|
||||
// ============================================
|
||||
"bwi-business": "business",
|
||||
"bwi-collection": "folder_shared",
|
||||
"bwi-collection-shared": "folder_shared", // Remove this - use collection instead
|
||||
"bwi-credit-card": "credit_card",
|
||||
"bwi-dashboard": "dashboard",
|
||||
"bwi-family": "family_restroom",
|
||||
"bwi-folder": "folder",
|
||||
"bwi-user": "person", // Was: bwi-users (singular)
|
||||
"bwi-users": "group", // Was: bwi-users (plural)
|
||||
"bwi-id-card": "badge", // Was: bwi-id-card
|
||||
"bwi-globe": "public", // login item type
|
||||
"bwi-sticky-note": "sticky_note_2", // Was: bwi-sticky-note
|
||||
"bwi-send": "send",
|
||||
"bwi-vault": "inventory_2",
|
||||
|
||||
// ============================================
|
||||
// ACTIONS
|
||||
// ============================================
|
||||
"bwi-plus": "add", // Was: bwi-plus
|
||||
"bwi-plus-circle": "add_circle", // Was: bwi-plus-circle
|
||||
"bwi-archive": "archive",
|
||||
"bwi-import": "upload_file", // Was: bwi-import (autofill is new)
|
||||
"bwi-check-circle": "check_circle",
|
||||
"bwi-clone": "content_copy", // Was: bwi-clone
|
||||
"bwi-close": "close",
|
||||
"bwi-download": "download",
|
||||
"bwi-pencil": "edit", // Was: bwi-pencil
|
||||
"bwi-pencil-square": "edit_note", // Was: bwi-pencil-square
|
||||
"bwi-lock-encrypted": "enhanced_encryption", // Was: bwi-lock-encrypted
|
||||
"bwi-external-link": "open_in_new",
|
||||
"bwi-files": "content_copy", // Was: bwi-files (duplicate action)
|
||||
"bwi-generate": "cached", // Was: bwi-generate
|
||||
"bwi-lock": "lock",
|
||||
"bwi-lock-f": "lock", // Was: bwi-lock-f (filled version)
|
||||
"bwi-envelope": "mail",
|
||||
"bwi-sign-in": "login",
|
||||
"bwi-sign-out": "logout",
|
||||
"bwi-popout": "open_in_new", // Was: bwi-popout (new-window)
|
||||
"bwi-refresh": "refresh",
|
||||
"bwi-search": "search",
|
||||
"bwi-cog": "settings", // Was: bwi-cog
|
||||
"bwi-cog-f": "settings", // Was: bwi-cog-f (filled version)
|
||||
"bwi-share": "share",
|
||||
"bwi-star": "star_outline",
|
||||
"bwi-star-f": "star",
|
||||
"bwi-minus-circle": "remove_circle", // Was: bwi-minus-circle (subtract-circle)
|
||||
"bwi-trash": "delete",
|
||||
"bwi-undo": "undo",
|
||||
"bwi-unlock": "lock_open",
|
||||
"bwi-eye": "visibility", // Was: bwi-eye
|
||||
"bwi-eye-slash": "visibility_off", // Was: bwi-eye-slash
|
||||
|
||||
// ============================================
|
||||
// ARROWS AND MENUS
|
||||
// ============================================
|
||||
"bwi-angle-down": "keyboard_arrow_down",
|
||||
"bwi-angle-left": "keyboard_arrow_left",
|
||||
"bwi-angle-right": "keyboard_arrow_right",
|
||||
"bwi-angle-up": "keyboard_arrow_up",
|
||||
"bwi-up-down-btn": "unfold_more", // Was: bwi-up-down-btn (angle-up-down)
|
||||
"bwi-down-solid": "arrow_drop_down", // Was: bwi-down-solid (arrow-filled-down)
|
||||
"bwi-up-solid": "arrow_drop_up", // Was: bwi-up-solid (arrow-filled-up)
|
||||
"bwi-drag-and-drop": "drag_indicator", // Was: bwi-drag-and-drop (drag)
|
||||
"bwi-ellipsis-h": "more_horiz",
|
||||
"bwi-ellipsis-v": "more_vert",
|
||||
"bwi-filter": "filter_list",
|
||||
"bwi-list-alt": "view_agenda", // Was: bwi-filter (grid)
|
||||
"bwi-list": "list",
|
||||
"bwi-numbered-list": "format_list_numbered", // Was: bwi-numbered-list (list-alt)
|
||||
"bwi-sliders": "tune",
|
||||
|
||||
// ============================================
|
||||
// MISCELLANEOUS
|
||||
// ============================================
|
||||
"bwi-universal-access": "accessibility", // Was: bwi-universal-access
|
||||
"bwi-paperclip": "attach_file", // Was: bwi-paperclip (attachment)
|
||||
"bwi-shield": "shield", // Was: bwi-shield (bitwarden-shield)
|
||||
"bwi-browser": "web",
|
||||
"bwi-bug": "bug_report",
|
||||
"bwi-camera": "photo_camera",
|
||||
"bwi-clock": "schedule",
|
||||
"bwi-desktop": "computer",
|
||||
"bwi-dollar": "attach_money", // Was: bwi-dollar
|
||||
"bwi-puzzle": "extension",
|
||||
"bwi-file": "description",
|
||||
"bwi-file-text": "article",
|
||||
"bwi-hashtag": "tag",
|
||||
"bwi-key": "vpn_key",
|
||||
"bwi-mobile": "smartphone",
|
||||
"bwi-msp": "business_center",
|
||||
"bwi-brush": "palette", // Was: bwi-brush
|
||||
"bwi-passkey": "password", // Was: bwi-passkey (using password icon)
|
||||
"bwi-bell": "notifications", // Was: bwi-bell (notifications)
|
||||
"bwi-billing": "receipt",
|
||||
"bwi-cli": "terminal",
|
||||
"bwi-tag": "label",
|
||||
"bwi-provider": "handshake", // Was: bwi-provider
|
||||
"bwi-wireless": "wifi",
|
||||
"bwi-wrench": "build",
|
||||
|
||||
// ============================================
|
||||
// 3RD PARTY PLATFORMS AND LOGOS
|
||||
// ============================================
|
||||
"bwi-bitcoin": "currency_bitcoin",
|
||||
"bwi-paypal": "payments",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Material Icon names that are NEW and don't have BWI equivalents
|
||||
* These should be added to the component library as new icons
|
||||
*/
|
||||
export const NEW_MATERIAL_ICONS = {
|
||||
autofill: "login", // New icon for autofill feature
|
||||
clear: "backspace", // New icon, differentiated from error
|
||||
redo: "redo", // New icon, should be coupled with undo
|
||||
subtract: "remove", // New icon (no outline version)
|
||||
"arrow-down": "south", // New icon for directional arrows
|
||||
"arrow-left": "west", // New icon
|
||||
"arrow-right": "east", // New icon
|
||||
"arrow-up": "north", // New icon
|
||||
"arrow-filled-left": "arrow_back", // New icon
|
||||
"arrow-filled-right": "arrow_forward", // New icon
|
||||
diamond: "diamond", // New icon for premium plans
|
||||
sso: "cloud", // New icon for single-sign-on
|
||||
"edit-alt": "edit", // Alternative edit icon
|
||||
duplicate: "content_copy", // Was: bwi-files
|
||||
"file-upload": "upload_file", // Was: bwi-import
|
||||
unarchive: "unarchive", // New icon
|
||||
grid: "grid_view", // Was: bwi-filter (different usage)
|
||||
} as const;
|
||||
|
||||
export type BwiIconName = keyof typeof BWI_TO_MATERIAL_MAPPING;
|
||||
export type MaterialIconName = (typeof BWI_TO_MATERIAL_MAPPING)[BwiIconName];
|
||||
export type NewMaterialIconName = keyof typeof NEW_MATERIAL_ICONS;
|
||||
|
||||
/**
|
||||
* Get Material Icon name from BWI icon name
|
||||
*/
|
||||
export function getMaterialIconName(bwiName: string): string | undefined {
|
||||
return BWI_TO_MATERIAL_MAPPING[bwiName as BwiIconName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if BWI icon has a Material Icon mapping
|
||||
*/
|
||||
export function hasMaterialMapping(bwiName: string): boolean {
|
||||
return bwiName in BWI_TO_MATERIAL_MAPPING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all BWI icon names that have Material mappings
|
||||
*/
|
||||
export function getMappedBwiIcons(): readonly BwiIconName[] {
|
||||
return Object.keys(BWI_TO_MATERIAL_MAPPING) as BwiIconName[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Material icon names used in mappings
|
||||
*/
|
||||
export function getMappedMaterialIcons(): readonly MaterialIconName[] {
|
||||
return Object.values(BWI_TO_MATERIAL_MAPPING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Icons that need attention based on Figma notes
|
||||
*/
|
||||
export const ICON_NOTES = {
|
||||
"bwi-collection-shared": "Remove this icon. Replace all instances with bwi-collection",
|
||||
"bwi-pencil-square": "Question: When should this be used in place of the edit-alt version?",
|
||||
"bwi-pencil": "Question: Move this icon from Misc Objects to Actions?",
|
||||
"bwi-down-solid":
|
||||
"All instances of the solid arrow used in tables to indicate sort order descending should be replaced with arrow-down",
|
||||
"bwi-up-solid":
|
||||
"All instances of the solid arrow used in tables to indicate sort order ascending should be replaced with arrow-up",
|
||||
"bwi-provider":
|
||||
"Replace instances of 'provider' icon used to indicate single-sign-on with the new sso icon",
|
||||
"bwi-filter":
|
||||
"Consider replacing the current sliders icon in the browser extension for this more standard filter icon",
|
||||
"bwi-brush": "Replace current 'brush' icon",
|
||||
} as const;
|
||||
Reference in New Issue
Block a user