feat: inline svg icons (#24)
4
.gitignore
vendored
@ -2,8 +2,8 @@ node_modules/
|
||||
dist/
|
||||
.wxt/
|
||||
|
||||
src/public/
|
||||
src/vscode-icons.json
|
||||
src/associations.json
|
||||
src/icons.json
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
@ -4,10 +4,12 @@
|
||||
"description": "Soothing pastel icons for GitHub File Explorer",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@catppuccin/palette": "1.1.1",
|
||||
"selector-observer": "2.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@humanfs/node": "0.14.0",
|
||||
"@humanfs/types": "0.13.0",
|
||||
"jiti": "1.21.0",
|
||||
"prettier": "3.2.5",
|
||||
"wxt": "0.17.3"
|
||||
|
||||
15
pnpm-lock.yaml
generated
@ -5,6 +5,9 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
'@catppuccin/palette':
|
||||
specifier: 1.1.1
|
||||
version: 1.1.1
|
||||
selector-observer:
|
||||
specifier: 2.1.6
|
||||
version: 2.1.6
|
||||
@ -13,6 +16,9 @@ devDependencies:
|
||||
'@humanfs/node':
|
||||
specifier: 0.14.0
|
||||
version: 0.14.0
|
||||
'@humanfs/types':
|
||||
specifier: 0.13.0
|
||||
version: 0.13.0
|
||||
jiti:
|
||||
specifier: 1.21.0
|
||||
version: 1.21.0
|
||||
@ -70,6 +76,10 @@ packages:
|
||||
regenerator-runtime: 0.14.1
|
||||
dev: true
|
||||
|
||||
/@catppuccin/palette@1.1.1:
|
||||
resolution: {integrity: sha512-wgITbl3OEIUnv8WPTdG2BGjepSMZtJW9V4XpxNDJjCvel0Q5+BxRmKH3XYN0vVjohHR+APCyZCpzSnO+GdsTLg==}
|
||||
dev: false
|
||||
|
||||
/@devicefarmer/adbkit-logcat@2.1.3:
|
||||
resolution: {integrity: sha512-yeaGFjNBc/6+svbDeul1tNHtNChw6h8pSHAt5D+JsedUrMTN7tla7B15WLDyekxsuS2XlZHRxpuC6m92wiwCNw==}
|
||||
engines: {node: '>= 4'}
|
||||
@ -316,6 +326,11 @@ packages:
|
||||
'@humanwhocodes/retry': 0.1.2
|
||||
dev: true
|
||||
|
||||
/@humanfs/types@0.13.0:
|
||||
resolution: {integrity: sha512-3QDsfgPh0XN4D5Wg89cmswDJWLtZI4iqt7N0MrRbJBfpE9LrTYMwNKHkfZupyN531hhYPsDOtCHhHhF75LWOrg==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
dev: true
|
||||
|
||||
/@humanwhocodes/retry@0.1.2:
|
||||
resolution: {integrity: sha512-JNWGHkYfWI0+YgRHOwkFKjOuelfypQtp0GSx0lsOP9jU1Tj4f8k0x4dcaJSEZTp61THZJ+f9PJRh1GzYlQqHOQ==}
|
||||
engines: {node: '>=18.18'}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import type { Associations } from './types';
|
||||
|
||||
import { associations as json } from '@/vscode-icons.json';
|
||||
import { customAssociations } from './storage';
|
||||
|
||||
import json from '@/associations.json';
|
||||
|
||||
export async function getAssociations(): Promise<Associations> {
|
||||
const custom = await customAssociations.getValue();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export const selectors = {
|
||||
export const SELECTORS = {
|
||||
row: `.js-navigation-container[role=grid] > .js-navigation-item,
|
||||
file-tree .ActionList-content,
|
||||
a.tree-browser-result,
|
||||
@ -22,3 +22,5 @@ export const selectors = {
|
||||
export const icons = {
|
||||
x: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" viewBox="0 0 256 256"><path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path></svg>',
|
||||
};
|
||||
|
||||
export const ATTRIBUTE_PREFIX = 'data-catppuccin-file-explorer-icons';
|
||||
@ -1,10 +1,10 @@
|
||||
import { defineContentScript } from 'wxt/sandbox';
|
||||
import './styles.css';
|
||||
|
||||
import { observe } from 'selector-observer';
|
||||
import { replaceAllIcons, replaceIconInRow } from '@/lib/replace';
|
||||
import { selectors } from '@/lib/constants';
|
||||
import { flavor } from '@/lib/storage';
|
||||
|
||||
import { SELECTORS } from '@/constants';
|
||||
import { flavor } from '@/storage';
|
||||
import { replaceIconInRow, injectStyles } from './lib';
|
||||
|
||||
export default defineContentScript({
|
||||
matches: ['*://github.com/*'],
|
||||
@ -16,7 +16,7 @@ export default defineContentScript({
|
||||
// Here we compromise, rushing the first n replacements to prevent blinks that will likely be "above the fold"
|
||||
// and delaying the replacement of subsequent rows.
|
||||
let executions = 0;
|
||||
let timerID;
|
||||
let timerID: NodeJS.Timeout;
|
||||
const rushFirst = (rushBatch: number, callback: () => void) => {
|
||||
if (executions <= rushBatch) {
|
||||
callback(); // Immediately run to prevent visual "blink".
|
||||
@ -32,16 +32,15 @@ export default defineContentScript({
|
||||
};
|
||||
|
||||
// Monitor DOM elements that match a CSS selector.
|
||||
observe(selectors.row, {
|
||||
observe(SELECTORS.row, {
|
||||
add(row) {
|
||||
const callback = async () =>
|
||||
await replaceIconInRow(row as HTMLElement);
|
||||
rushFirst(90, callback);
|
||||
},
|
||||
});
|
||||
// Monitor the flavor changing.
|
||||
flavor.watch(replaceAllIcons);
|
||||
|
||||
replaceAllIcons();
|
||||
flavor.watch(injectStyles);
|
||||
injectStyles();
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,20 +1,69 @@
|
||||
import type { PublicPath } from 'wxt/browser';
|
||||
import type { IconName } from '@/lib/types';
|
||||
import type { IconName } from '@/types';
|
||||
|
||||
import { selectors } from '@/lib/constants';
|
||||
import { flavor, specificFolders } from '@/lib/storage';
|
||||
import { getAssociations } from './associations';
|
||||
import { ATTRIBUTE_PREFIX, SELECTORS } from '@/constants';
|
||||
import { flavor, specificFolders } from '@/storage';
|
||||
import { getAssociations } from '@/associations';
|
||||
import { createStylesElement } from '@/utils';
|
||||
|
||||
import { flavors } from '@catppuccin/palette';
|
||||
|
||||
import icons from '@/icons.json';
|
||||
|
||||
export async function injectStyles() {
|
||||
const styles = createStylesElement();
|
||||
|
||||
styles.textContent = /* css */ `
|
||||
:root {
|
||||
${flavors[await flavor.getValue()].colorEntries
|
||||
.map(([name, { hex }]) => `--ctp-${name}: ${hex};`)
|
||||
.join('\n ')}
|
||||
}
|
||||
|
||||
.PRIVATE_TreeView-directory-icon svg {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
svg[${ATTRIBUTE_PREFIX}-iconname$='_open']:has(~ svg.octicon-file-directory-open-fill:not([data-catppuccin-file-explorer-icons])),
|
||||
svg:not([${ATTRIBUTE_PREFIX}-iconname$='_open']):has(~ svg.octicon-file-directory-fill:not([data-catppuccin-file-explorer-icons])),
|
||||
svg[${ATTRIBUTE_PREFIX}]:has(+ .octicon-file) {
|
||||
display: inline-block !important;
|
||||
}
|
||||
`.trim();
|
||||
}
|
||||
|
||||
function createIconElement(
|
||||
iconName: IconName,
|
||||
fileName: string,
|
||||
originalIcon: HTMLElement,
|
||||
): SVGSVGElement {
|
||||
let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
svg.innerHTML = icons[iconName];
|
||||
svg.setAttribute(ATTRIBUTE_PREFIX, '');
|
||||
svg.setAttribute(`${ATTRIBUTE_PREFIX}-iconname`, iconName);
|
||||
svg.setAttribute(`${ATTRIBUTE_PREFIX}-filename`, fileName);
|
||||
|
||||
for (const attribute of originalIcon.getAttributeNames()) {
|
||||
if (!attribute.startsWith(ATTRIBUTE_PREFIX)) {
|
||||
svg.setAttribute(
|
||||
attribute,
|
||||
originalIcon.getAttribute(attribute) as string,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return svg;
|
||||
}
|
||||
|
||||
export async function replaceIconInRow(row: HTMLElement) {
|
||||
const icon = row.querySelector(selectors.icon) as HTMLElement;
|
||||
if (icon && !icon?.hasAttribute('data-catppuccin-extension'))
|
||||
const icon = row.querySelector(SELECTORS.icon) as HTMLElement;
|
||||
if (icon && !icon?.hasAttribute(ATTRIBUTE_PREFIX))
|
||||
await replaceIcon(icon, row);
|
||||
}
|
||||
|
||||
export async function replaceIcon(icon: HTMLElement, row: HTMLElement) {
|
||||
const fileNameEl = row.querySelector(selectors.filename) as HTMLElement;
|
||||
const fileNameEl = row.querySelector(SELECTORS.filename) as HTMLElement;
|
||||
if (!fileNameEl) return;
|
||||
const fileName = fileNameEl.textContent?.split('/')[0].trim();
|
||||
const fileName = fileNameEl.textContent?.split('/').at(0).trim();
|
||||
|
||||
const isDir =
|
||||
icon.getAttribute('aria-label') === 'Directory' ||
|
||||
@ -58,27 +107,14 @@ export async function replaceElementWithIcon(
|
||||
iconName: IconName,
|
||||
fileName: string,
|
||||
) {
|
||||
const replacement = document.createElement('img');
|
||||
replacement.setAttribute('data-catppuccin-extension', 'icon');
|
||||
replacement.setAttribute('data-catppuccin-extension-iconname', iconName);
|
||||
replacement.setAttribute('data-catppuccin-extension-filename', fileName);
|
||||
replacement.src = browser.runtime.getURL(
|
||||
`${await flavor.getValue()}/${iconName}.svg` as PublicPath,
|
||||
);
|
||||
|
||||
icon.getAttributeNames().forEach(
|
||||
(attr) =>
|
||||
attr !== 'src' &&
|
||||
!/^data-catppuccin-extension/.test(attr) &&
|
||||
replacement.setAttribute(attr, icon.getAttribute(attr) as string),
|
||||
);
|
||||
const replacement = createIconElement(iconName, fileName, icon);
|
||||
|
||||
const prevEl = icon.previousElementSibling;
|
||||
if (prevEl?.getAttribute('data-catppuccin-extension') === 'icon') {
|
||||
if (prevEl?.hasAttribute(ATTRIBUTE_PREFIX)) {
|
||||
replacement.replaceWith(prevEl);
|
||||
}
|
||||
// If the icon to replace is an icon from this extension, replace it with the new icon.
|
||||
else if (icon.getAttribute('data-catppuccin-extension') === 'icon') {
|
||||
else if (icon.hasAttribute(ATTRIBUTE_PREFIX)) {
|
||||
icon.replaceWith(replacement);
|
||||
}
|
||||
// If neither of the above, prepend the new icon in front of the original icon.
|
||||
@ -88,29 +124,19 @@ export async function replaceElementWithIcon(
|
||||
icon.style.display = 'none';
|
||||
icon.before(replacement);
|
||||
}
|
||||
|
||||
if (
|
||||
icon.parentElement.classList.contains('PRIVATE_TreeView-directory-icon')
|
||||
) {
|
||||
const button =
|
||||
icon.parentElement.parentElement.parentElement
|
||||
.previousElementSibling;
|
||||
const row = button.parentElement;
|
||||
button.addEventListener('click', () => {
|
||||
if (replacement.src.includes('_open')) {
|
||||
replacement.setAttribute('data-do-not-touch', 'true');
|
||||
replacement.src = replacement.src.replace('_open', '');
|
||||
} else {
|
||||
replacement.src = replacement.src.replace('.svg', '_open.svg');
|
||||
}
|
||||
});
|
||||
row.addEventListener('click', () => {
|
||||
if (
|
||||
!replacement.src.includes('_open') &&
|
||||
replacement.getAttribute('data-do-not-touch') !== 'true'
|
||||
) {
|
||||
replacement.src = replacement.src.replace('.svg', '_open.svg');
|
||||
}
|
||||
});
|
||||
let companion = createIconElement(
|
||||
(iconName.includes('_open')
|
||||
? iconName.replace('_open', '')
|
||||
: iconName + '_open') as IconName,
|
||||
fileName,
|
||||
icon,
|
||||
);
|
||||
|
||||
replacement.after(companion);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,18 +179,3 @@ async function findIconMatch(
|
||||
return '_file';
|
||||
}
|
||||
}
|
||||
|
||||
export function replaceAllIcons() {
|
||||
for (const icon of document.querySelectorAll(
|
||||
'img[data-catppuccin-extension-iconname]',
|
||||
) as NodeListOf<HTMLElement>) {
|
||||
const iconName = icon.getAttribute(
|
||||
'data-catppuccin-extension-iconname',
|
||||
) as IconName;
|
||||
const fileName = icon.getAttribute(
|
||||
'data-catppuccin-extension-filename',
|
||||
);
|
||||
if (iconName && fileName)
|
||||
replaceElementWithIcon(icon, iconName, fileName);
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
.catppuccin-exension-hide-pseudo::before {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide folder open/closed icons from new code view tree when clicked by disabling
|
||||
display of those icons when they immediately follow the replaced icon. */
|
||||
img[data-catppuccin-extension='icon'] + svg.octicon-file-directory-open-fill,
|
||||
img[data-catppuccin-extension='icon'] + svg.octicon-file-directory-fill {
|
||||
display: none !important;
|
||||
}
|
||||
@ -1,11 +1,29 @@
|
||||
import './styles.css';
|
||||
|
||||
import type { Associations, Flavor, IconName } from '@/lib/types';
|
||||
import type { Associations, Flavor, IconName } from '@/types';
|
||||
|
||||
import { customAssociations, flavor, specificFolders } from '@/lib/storage';
|
||||
import { icons } from '@/lib/constants';
|
||||
import { flavor, specificFolders, customAssociations } from '@/storage';
|
||||
import { icons } from '@/constants';
|
||||
import { createStylesElement } from '@/utils';
|
||||
|
||||
import { flavorEntries } from '@catppuccin/palette';
|
||||
|
||||
function injectStyles() {
|
||||
const styles = createStylesElement();
|
||||
|
||||
styles.textContent = flavorEntries
|
||||
.map(
|
||||
([flavor, { colorEntries }]) =>
|
||||
`:root[theme="${flavor}"] {\n${colorEntries.map(([name, { hex }]) => ` --ctp-${name}: ${hex};`).join('\n')}\n}`,
|
||||
)
|
||||
.join('\n');
|
||||
|
||||
document.documentElement.appendChild(styles);
|
||||
}
|
||||
|
||||
async function init() {
|
||||
injectStyles();
|
||||
|
||||
const flavorEl = document.querySelector('#flavor') as HTMLSelectElement;
|
||||
|
||||
flavorEl.value = await flavor.getValue();
|
||||
|
||||
@ -1,123 +1,3 @@
|
||||
:root[theme='latte'] {
|
||||
color-scheme: light;
|
||||
--ctp-rosewater: #dc8a78;
|
||||
--ctp-flamingo: #dd7878;
|
||||
--ctp-pink: #ea76cb;
|
||||
--ctp-mauve: #8839ef;
|
||||
--ctp-red: #d20f39;
|
||||
--ctp-maroon: #e64553;
|
||||
--ctp-peach: #fe640b;
|
||||
--ctp-yellow: #df8e1d;
|
||||
--ctp-green: #40a02b;
|
||||
--ctp-teal: #179299;
|
||||
--ctp-sky: #04a5e5;
|
||||
--ctp-sapphire: #209fb5;
|
||||
--ctp-blue: #1e66f5;
|
||||
--ctp-lavender: #7287fd;
|
||||
--ctp-text: #4c4f69;
|
||||
--ctp-subtext1: #5c5f77;
|
||||
--ctp-subtext0: #6c6f85;
|
||||
--ctp-overlay2: #7c7f93;
|
||||
--ctp-overlay1: #8c8fa1;
|
||||
--ctp-overlay0: #9ca0b0;
|
||||
--ctp-surface2: #acb0be;
|
||||
--ctp-surface1: #bcc0cc;
|
||||
--ctp-surface0: #ccd0da;
|
||||
--ctp-base: #eff1f5;
|
||||
--ctp-mantle: #e6e9ef;
|
||||
--ctp-crust: #dce0e8;
|
||||
}
|
||||
|
||||
:root[theme='frappe'] {
|
||||
color-scheme: dark;
|
||||
--ctp-rosewater: #f2d5cf;
|
||||
--ctp-flamingo: #eebebe;
|
||||
--ctp-pink: #f4b8e4;
|
||||
--ctp-mauve: #ca9ee6;
|
||||
--ctp-red: #e78284;
|
||||
--ctp-maroon: #ea999c;
|
||||
--ctp-peach: #ef9f76;
|
||||
--ctp-yellow: #e5c890;
|
||||
--ctp-green: #a6d189;
|
||||
--ctp-teal: #81c8be;
|
||||
--ctp-sky: #99d1db;
|
||||
--ctp-sapphire: #85c1dc;
|
||||
--ctp-blue: #8caaee;
|
||||
--ctp-lavender: #babbf1;
|
||||
--ctp-text: #c6d0f5;
|
||||
--ctp-subtext1: #b5bfe2;
|
||||
--ctp-subtext0: #a5adce;
|
||||
--ctp-overlay2: #949cbb;
|
||||
--ctp-overlay1: #838ba7;
|
||||
--ctp-overlay0: #737994;
|
||||
--ctp-surface2: #626880;
|
||||
--ctp-surface1: #51576d;
|
||||
--ctp-surface0: #414559;
|
||||
--ctp-base: #303446;
|
||||
--ctp-mantle: #292c3c;
|
||||
--ctp-crust: #232634;
|
||||
}
|
||||
|
||||
:root[theme='macchiato'] {
|
||||
color-scheme: dark;
|
||||
--ctp-rosewater: #f4dbd6;
|
||||
--ctp-flamingo: #f0c6c6;
|
||||
--ctp-pink: #f5bde6;
|
||||
--ctp-mauve: #c6a0f6;
|
||||
--ctp-red: #ed8796;
|
||||
--ctp-maroon: #ee99a0;
|
||||
--ctp-peach: #f5a97f;
|
||||
--ctp-yellow: #eed49f;
|
||||
--ctp-green: #a6da95;
|
||||
--ctp-teal: #8bd5ca;
|
||||
--ctp-sky: #91d7e3;
|
||||
--ctp-sapphire: #7dc4e4;
|
||||
--ctp-blue: #8aadf4;
|
||||
--ctp-lavender: #b7bdf8;
|
||||
--ctp-text: #cad3f5;
|
||||
--ctp-subtext1: #b8c0e0;
|
||||
--ctp-subtext0: #a5adcb;
|
||||
--ctp-overlay2: #939ab7;
|
||||
--ctp-overlay1: #8087a2;
|
||||
--ctp-overlay0: #6e738d;
|
||||
--ctp-surface2: #5b6078;
|
||||
--ctp-surface1: #494d64;
|
||||
--ctp-surface0: #363a4f;
|
||||
--ctp-base: #24273a;
|
||||
--ctp-mantle: #1e2030;
|
||||
--ctp-crust: #181926;
|
||||
}
|
||||
|
||||
:root[theme='mocha'] {
|
||||
color-scheme: dark;
|
||||
--ctp-rosewater: #f5e0dc;
|
||||
--ctp-flamingo: #f2cdcd;
|
||||
--ctp-pink: #f5c2e7;
|
||||
--ctp-mauve: #cba6f7;
|
||||
--ctp-red: #f38ba8;
|
||||
--ctp-maroon: #eba0ac;
|
||||
--ctp-peach: #fab387;
|
||||
--ctp-yellow: #f9e2af;
|
||||
--ctp-green: #a6e3a1;
|
||||
--ctp-teal: #94e2d5;
|
||||
--ctp-sky: #89dceb;
|
||||
--ctp-sapphire: #74c7ec;
|
||||
--ctp-blue: #89b4fa;
|
||||
--ctp-lavender: #b4befe;
|
||||
--ctp-text: #cdd6f4;
|
||||
--ctp-subtext1: #bac2de;
|
||||
--ctp-subtext0: #a6adc8;
|
||||
--ctp-overlay2: #9399b2;
|
||||
--ctp-overlay1: #7f849c;
|
||||
--ctp-overlay0: #6c7086;
|
||||
--ctp-surface2: #585b70;
|
||||
--ctp-surface1: #45475a;
|
||||
--ctp-surface0: #313244;
|
||||
--ctp-base: #1e1e2e;
|
||||
--ctp-mantle: #181825;
|
||||
--ctp-crust: #11111b;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 600px;
|
||||
height: max-content;
|
||||
|
||||
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
@ -1,10 +1,8 @@
|
||||
import type { PublicPath } from 'wxt/browser';
|
||||
import icons from '@/icons.json';
|
||||
|
||||
export type Flavor = 'latte' | 'frappe' | 'macchiato' | 'mocha';
|
||||
|
||||
type RemoveIconPrefixAndSuffix<T extends string> =
|
||||
T extends `/${Flavor}/${infer Rest}.svg` ? Rest : never;
|
||||
export type IconName = RemoveIconPrefixAndSuffix<PublicPath>;
|
||||
export type IconName = keyof typeof icons;
|
||||
|
||||
export type Associations = {
|
||||
languageIds: Record<string, IconName>;
|
||||
13
src/utils.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export function createStylesElement() {
|
||||
const id = 'catppuccin-icons-css-variables';
|
||||
|
||||
let styles = document.querySelector(`#${id}`);
|
||||
|
||||
if (!styles) {
|
||||
styles = document.createElement('style');
|
||||
styles.setAttribute('id', id);
|
||||
document.documentElement.appendChild(styles);
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
@ -14,41 +14,41 @@ export default defineConfig({
|
||||
permissions: ['storage'],
|
||||
homepage_url:
|
||||
'https://github.com/catppuccin/github-file-explorer-icons',
|
||||
web_accessible_resources: [
|
||||
{
|
||||
resources: ['*.svg'],
|
||||
matches: ['*://github.com/*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
hooks: {
|
||||
'build:before': async () => {
|
||||
const PUBLIC_DIR = join(__dirname, './src/public/');
|
||||
if (await hfs.isDirectory(PUBLIC_DIR)) {
|
||||
await hfs.deleteAll(PUBLIC_DIR);
|
||||
await hfs.createDirectory(PUBLIC_DIR);
|
||||
const ICON_DIR = join(
|
||||
__dirname,
|
||||
'./vscode-icons/icons/css-variables/',
|
||||
);
|
||||
const icons = {};
|
||||
|
||||
for await (const entry of hfs.list(ICON_DIR)) {
|
||||
icons[entry.name.replace('.svg', '')] = await hfs
|
||||
.text(join(ICON_DIR, entry.name))
|
||||
.then((text) => {
|
||||
const lines = text.split('\n');
|
||||
return lines
|
||||
.slice(1, lines.length - 2)
|
||||
.join('\n')
|
||||
.trim()
|
||||
.replaceAll('--vscode-ctp', '--ctp')
|
||||
.replaceAll('/>', '></path>');
|
||||
});
|
||||
}
|
||||
|
||||
// Copy icons:
|
||||
await hfs.copyAll(
|
||||
join(__dirname, './vscode-icons/icons/'),
|
||||
PUBLIC_DIR,
|
||||
);
|
||||
await hfs.deleteAll(join(PUBLIC_DIR, 'css-variables'));
|
||||
|
||||
// Write associations/config file:
|
||||
await hfs.write(
|
||||
join(__dirname, './src/vscode-icons.json'),
|
||||
join(__dirname, './src/icons.json'),
|
||||
JSON.stringify(icons),
|
||||
);
|
||||
|
||||
await hfs.write(
|
||||
join(__dirname, './src/associations.json'),
|
||||
JSON.stringify(
|
||||
jiti(__dirname)('./vscode-icons/src/defaults/index.ts')
|
||||
.defaultConfig,
|
||||
.defaultConfig.associations,
|
||||
),
|
||||
);
|
||||
|
||||
await hfs.copyAll(
|
||||
join(__dirname, './assets/icons'),
|
||||
join(PUBLIC_DIR),
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||