Add more theme stuff, add a smidge of content

This commit is contained in:
2024-08-08 11:07:08 -04:00
parent 80c987ca91
commit e6340a906b
1138 changed files with 194811 additions and 5 deletions

View File

@@ -0,0 +1,6 @@
{
"rules": {
"import/no-extraneous-dependencies": "off",
"no-console": "off"
}
}

View File

@@ -0,0 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`builds object correctly 1`] = `
Object {
"icon1": "<line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"></line><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"></line>",
"icon2": "<circle cx=\\"12\\" cy=\\"12\\" r=\\"11\\"></circle>",
}
`;

View File

@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`builds sprite correctly 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\"><defs><symbol id=\\"icon1\\" viewBox=\\"0 0 24 24\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"></line><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"></line></symbol><symbol id=\\"icon2\\" viewBox=\\"0 0 24 24\\"><circle cx=\\"12\\" cy=\\"12\\" r=\\"11\\"></circle></symbol></defs></svg>"`;

View File

@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`optimizes SVG correctly 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"2\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\"><line x1=\\"23\\" y1=\\"1\\" x2=\\"1\\" y2=\\"23\\"/><line x1=\\"1\\" y1=\\"1\\" x2=\\"23\\" y2=\\"23\\"/></svg>"`;
exports[`rejects when passed unparsable SVG string 1`] = `
[Error: Error in parsing SVG: Unclosed root tag
Line: 0
Column: 10
Char: ]
`;

View File

@@ -0,0 +1,17 @@
/* eslint-env jest */
import buildIconsObject from '../build-icons-object';
const SVG_FILES = {
'icon1.svg':
'<svg\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n>\n <line x1="23" y1="1" x2="1" y2="23" />\n <line x1="1" y1="1" x2="23" y2="23" />\n</svg>',
'icon2.svg':
'<svg\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n>\n <circle cx="12" cy="12" r="11" />\n</svg>',
};
function getSvg(svgFile) {
return SVG_FILES[svgFile];
}
test('builds object correctly', () => {
expect(buildIconsObject(Object.keys(SVG_FILES), getSvg)).toMatchSnapshot();
});

View File

@@ -0,0 +1,12 @@
/* eslint-env jest */
import buildSpriteString from '../build-sprite-string';
const icons = {
icon1:
'<line x1="23" y1="1" x2="1" y2="23"></line><line x1="1" y1="1" x2="23" y2="23"></line>',
icon2: '<circle cx="12" cy="12" r="11"></circle>',
};
test('builds sprite correctly', () => {
expect(buildSpriteString(icons)).toMatchSnapshot();
});

View File

@@ -0,0 +1,15 @@
/* eslint-env jest */
import optimizeSvg from '../optimize-svg';
test('optimizes SVG correctly', () => {
const SVG =
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><title>Title</title><line x1="23" y1="1" x2="1" y2="23" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/><line x1="1" y1="1" x2="23" y2="23" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>';
expect(optimizeSvg(SVG)).resolves.toMatchSnapshot();
});
test('rejects when passed unparsable SVG string', () => {
const UNPARSABLE_SVG = '<svg></svg';
expect(optimizeSvg(UNPARSABLE_SVG)).rejects.toMatchSnapshot();
});

View File

@@ -0,0 +1,19 @@
import fs from 'fs';
import path from 'path';
import buildIconsObject from './build-icons-object';
const IN_DIR = path.resolve(__dirname, '../icons');
const OUT_FILE = path.resolve(__dirname, '../dist/icons.json');
console.log(`Building ${OUT_FILE}...`);
const svgFiles = fs
.readdirSync(IN_DIR)
.filter(file => path.extname(file) === '.svg');
const getSvg = svgFile => fs.readFileSync(path.join(IN_DIR, svgFile));
const icons = buildIconsObject(svgFiles, getSvg);
fs.writeFileSync(OUT_FILE, JSON.stringify(icons));

View File

@@ -0,0 +1,35 @@
import path from 'path';
import cheerio from 'cheerio';
import { minify } from 'html-minifier';
/**
* Build an object in the format: `{ <name>: <contents> }`.
* @param {string[]} svgFiles - A list of filenames.
* @param {Function} getSvg - A function that returns the contents of an SVG file given a filename.
* @returns {Object}
*/
function buildIconsObject(svgFiles, getSvg) {
return svgFiles
.map(svgFile => {
const name = path.basename(svgFile, '.svg');
const svg = getSvg(svgFile);
const contents = getSvgContents(svg);
return { name, contents };
})
.reduce((icons, icon) => {
icons[icon.name] = icon.contents;
return icons;
}, {});
}
/**
* Get contents between opening and closing `<svg>` tags.
* @param {string} svg
* @returns {string}
*/
function getSvgContents(svg) {
const $ = cheerio.load(svg);
return minify($('svg').html(), { collapseWhitespace: true });
}
export default buildIconsObject;

View File

@@ -0,0 +1,26 @@
import DEFAULT_ATTRS from '../src/default-attrs.json';
/**
* Build an SVG sprite string containing SVG symbols.
* @param {Object} icons
* @returns {string}
*/
function buildSpriteString(icons) {
const symbols = Object.keys(icons)
.map(icon => toSvgSymbol(icon, icons[icon]))
.join('');
return `<svg xmlns="${DEFAULT_ATTRS.xmlns}"><defs>${symbols}</defs></svg>`;
}
/**
* Create an SVG symbol string.
* @param {string} name - Icon name
* @param {string} contents - SVG contents
* @returns {string}
*/
function toSvgSymbol(name, contents) {
return `<symbol id="${name}" viewBox="${DEFAULT_ATTRS.viewBox}">${contents}</symbol>`;
}
export default buildSpriteString;

View File

@@ -0,0 +1,10 @@
import fs from 'fs';
import path from 'path';
import icons from '../dist/icons.json';
import buildSpriteString from './build-sprite-string';
const OUT_FILE = path.resolve(__dirname, '../dist/feather-sprite.svg');
console.log(`Building ${OUT_FILE}...`);
fs.writeFileSync(OUT_FILE, buildSpriteString(icons));

View File

@@ -0,0 +1,13 @@
import fs from 'fs';
import path from 'path';
import icons from '../src/icons';
const OUT_DIR = path.resolve(__dirname, '../dist/icons');
console.log(`Building SVGs in ${OUT_DIR}...`);
Object.keys(icons).forEach(name => {
const svg = icons[name].toSvg();
fs.writeFileSync(path.join(OUT_DIR, `${name}.svg`), svg);
});

22
public/js/feather/bin/build.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
# Create dist directory
npx rimraf dist
mkdir dist
# Build icons.json
npx babel-node bin/build-icons-json.js
# Build SVG sprite
npx babel-node bin/build-sprite.js
# Create dist/icons directory
npx rimraf dist/icons
mkdir dist/icons
# Build SVG icons
npx babel-node bin/build-svgs.js
# Build JavaScript library
npx webpack --output-filename feather.js --mode development
npx webpack --output-filename feather.min.js --mode production

View File

@@ -0,0 +1,50 @@
import Svgo from 'svgo';
import cheerio from 'cheerio';
import DEFAULT_ATTRS from '../src/default-attrs.json';
/**
* Optimize SVG string.
* @param {string} svg - An SVG string.
* @returns {Promise<string>}
*/
function optimizeSvg(svg) {
return svgo(svg).then(setAttrs);
}
/**
* Run SVGO on SVG string.
* @param {string} svg - An SVG string.
* @returns {Promise<string>}
*/
function svgo(svg) {
const s = new Svgo({
plugins: [
{ convertShapeToPath: false },
{ mergePaths: false },
{ removeAttrs: { attrs: '(fill|stroke.*)' } },
{ removeTitle: true },
],
});
return new Promise(resolve => {
s.optimize(svg, ({ data }) => resolve(data));
});
}
/**
* Set default attributes on SVG.
* @param {string} svg - An SVG string.
* @returns {string}
*/
function setAttrs(svg) {
const $ = cheerio.load(svg);
Object.keys(DEFAULT_ATTRS).forEach(key =>
$('svg').attr(key, DEFAULT_ATTRS[key]),
);
return $('body').html();
}
export default optimizeSvg;

View File

@@ -0,0 +1,17 @@
import fs from 'fs';
import path from 'path';
import optimizeSvg from './optimize-svg';
const IN_DIR = path.resolve(__dirname, '../icons');
console.log(`Optimizing SVGs in ${IN_DIR}...`);
fs.readdirSync(IN_DIR)
.filter(file => path.extname(file) === '.svg')
.forEach(svgFile => {
const svg = fs.readFileSync(path.join(IN_DIR, svgFile));
optimizeSvg(svg).then(svg =>
fs.writeFileSync(path.join(IN_DIR, svgFile), svg),
);
});

6
public/js/feather/bin/setup.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
npm install --legacy-peer-deps
npm run build
npm run test:coverage
npm run lint