├── .artifacts.yml ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .publisher.yml ├── .stylelintrc ├── .travis.yml ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── MIGRATION_GUIDES.md ├── README.md ├── assembly-logo.svg ├── babel.config.json ├── batfish.config.js ├── index.js ├── nodemon.json ├── package-lock.json ├── package.json ├── scripts ├── build-color-variants.js ├── build-css.js ├── build-icon-json.js ├── build-js.js ├── build-layout-scales.js ├── build-media-variants.js ├── build-navigation-json.js ├── build-svg-loader.js ├── build-user-assets.js ├── check-size.js ├── clean-svgs.js ├── deploy.js ├── order-sections.js ├── timelog.js └── watch-assembly-assets.js ├── site ├── .eslintrc.json ├── application_wrapper.js ├── catalog │ ├── bleeds.js │ ├── buttons.js │ ├── checkboxes.js │ ├── flexbox.js │ ├── grids.js │ ├── inputs.js │ ├── links.js │ ├── lists.js │ ├── pills.js │ ├── radios.js │ ├── ranges.js │ ├── selects.js │ ├── switches.js │ ├── tables.js │ ├── textareas.js │ ├── toggles.js │ ├── triangles.js │ └── typography.js ├── css │ └── hljs.css ├── entry.js ├── heading.js ├── html_example.js ├── html_template.js ├── img │ ├── baseline-grid.svg │ ├── box-model.svg │ ├── custom-icons.svg │ ├── defaults.svg │ ├── focus.svg │ ├── is-active.svg │ ├── media-queries.svg │ ├── modifier.svg │ ├── spacedog800.jpg │ └── specificity.svg ├── js │ └── copy.js ├── logo.js ├── navigation.js ├── page.js └── pages │ ├── catalog.js │ ├── documentation.js │ ├── examples │ ├── badges.js │ ├── equal-height-columns.js │ ├── index.js │ ├── inputs.js │ ├── legends.js │ ├── modal.js │ ├── navigation.js │ ├── progress-bars.js │ ├── sidebar-apps.js │ ├── spinner.js │ └── tooltips.js │ ├── favicon.ico │ ├── icons.js │ ├── index.js │ └── layout-scales.js ├── src ├── animations.css ├── buttons.css ├── color-variants.css ├── colors.css ├── focus.css ├── fonts.css ├── forms.css ├── icons.css ├── js │ ├── .eslintrc │ ├── focus-control.js │ └── icon-functions.js ├── layout-scales.css ├── layout.css ├── links.css ├── md4-shim.js ├── media-queries.json ├── miscellaneous.css ├── reset.css ├── scales.json ├── svgs │ ├── airplane.svg │ ├── alert.svg │ ├── android.svg │ ├── arrive.svg │ ├── arrow-down.svg │ ├── arrow-left-right.svg │ ├── arrow-left.svg │ ├── arrow-right.svg │ ├── arrow-up-down.svg │ ├── arrow-up.svg │ ├── battery.svg │ ├── bear-left.svg │ ├── bear-right.svg │ ├── bell.svg │ ├── bike.svg │ ├── book.svg │ ├── bookmark.svg │ ├── boolean.svg │ ├── bug.svg │ ├── cap-butt.svg │ ├── cap-round.svg │ ├── cap-square.svg │ ├── car.svg │ ├── caret-down.svg │ ├── caret-left.svg │ ├── caret-right.svg │ ├── caret-up.svg │ ├── cart.svg │ ├── charger.svg │ ├── check.svg │ ├── chevron-down.svg │ ├── chevron-left.svg │ ├── chevron-right.svg │ ├── chevron-up.svg │ ├── circle.svg │ ├── clipboard.svg │ ├── clock.svg │ ├── close.svg │ ├── cloud.svg │ ├── code.svg │ ├── combine.svg │ ├── compass.svg │ ├── contact.svg │ ├── creditcard.svg │ ├── crosshair.svg │ ├── cursor.svg │ ├── database.svg │ ├── depart.svg │ ├── document.svg │ ├── drag.svg │ ├── drone.svg │ ├── duplicate.svg │ ├── eject.svg │ ├── elipse.svg │ ├── enter-roundabout.svg │ ├── extrusion.svg │ ├── eye.svg │ ├── fast-forward.svg │ ├── fill.svg │ ├── filter.svg │ ├── flame.svg │ ├── floppy.svg │ ├── folder-move.svg │ ├── folder.svg │ ├── font.svg │ ├── forward.svg │ ├── fullscreen.svg │ ├── github.svg │ ├── globe.svg │ ├── graph.svg │ ├── grid.svg │ ├── hand.svg │ ├── harddrive.svg │ ├── hash.svg │ ├── heart.svg │ ├── history.svg │ ├── home.svg │ ├── horizon.svg │ ├── info.svg │ ├── inspect.svg │ ├── interact.svg │ ├── ios.svg │ ├── join-bevel.svg │ ├── join-miter.svg │ ├── join-round.svg │ ├── layers.svg │ ├── lightning.svg │ ├── line-center.svg │ ├── line-poly.svg │ ├── line.svg │ ├── link.svg │ ├── lock.svg │ ├── logout.svg │ ├── mail.svg │ ├── map.svg │ ├── mapbox.svg │ ├── marker.svg │ ├── menu.svg │ ├── minus.svg │ ├── mobile.svg │ ├── model.svg │ ├── moon.svg │ ├── mountain.svg │ ├── noeye.svg │ ├── opacity.svg │ ├── open-in.svg │ ├── options.svg │ ├── osm.svg │ ├── package.svg │ ├── paint.svg │ ├── palette.svg │ ├── pause.svg │ ├── pen.svg │ ├── pencil.svg │ ├── picture.svg │ ├── play.svg │ ├── plus.svg │ ├── point-line-poly.svg │ ├── point-line.svg │ ├── point-poly.svg │ ├── polygon.svg │ ├── polyline.svg │ ├── position.svg │ ├── printer.svg │ ├── question.svg │ ├── quotes.svg │ ├── raster.svg │ ├── redo.svg │ ├── refresh.svg │ ├── return.svg │ ├── rotate.svg │ ├── rss.svg │ ├── satellite.svg │ ├── search.svg │ ├── select.svg │ ├── share.svg │ ├── sharp-left.svg │ ├── sharp-right.svg │ ├── shrink.svg │ ├── slot.svg │ ├── smooth-ramp.svg │ ├── snow.svg │ ├── speaker.svg │ ├── split.svg │ ├── sprocket.svg │ ├── square.svg │ ├── star.svg │ ├── step-ramp.svg │ ├── street.svg │ ├── sun.svg │ ├── swipe.svg │ ├── sync.svg │ ├── text-align-bottom-center.svg │ ├── text-align-bottom-left.svg │ ├── text-align-bottom-right.svg │ ├── text-align-center-center.svg │ ├── text-align-center-left.svg │ ├── text-align-center-right.svg │ ├── text-align-top-center.svg │ ├── text-align-top-left.svg │ ├── text-align-top-right.svg │ ├── text-justify-center.svg │ ├── text-justify-left.svg │ ├── text-justify-right.svg │ ├── text-size.svg │ ├── tileset.svg │ ├── transform-lowercase.svg │ ├── transform-uppercase.svg │ ├── trash.svg │ ├── turn-left.svg │ ├── turn-right.svg │ ├── twitter.svg │ ├── u-turn.svg │ ├── uncombine.svg │ ├── undo.svg │ ├── unlock.svg │ ├── user.svg │ ├── video.svg │ ├── viewport.svg │ ├── walk.svg │ └── water.svg ├── tables.css ├── theming.css ├── triangles.css ├── typography.css └── variables.json └── test ├── .eslintrc.json ├── __snapshots__ ├── build-color-variants.jest.js.snap ├── build-css.jest.js.snap ├── build-js.jest.js.snap ├── build-layout-scales.jest.js.snap └── build-media-variants.jest.js.snap ├── build-color-variants.jest.js ├── build-css.jest.js ├── build-js.jest.js ├── build-layout-scales.jest.js ├── build-media-variants.jest.js ├── build-user-assets.jest.js ├── fixtures ├── a.css └── b.css └── test-icons.tape.js /.artifacts.yml: -------------------------------------------------------------------------------- 1 | version: v1 2 | publisher: 3 | builds: 4 | - filter: on-branch 5 | name: publisher-branches 6 | config: 7 | node_version: 18.x 8 | site_build_dir: _site 9 | npm_build_script: build 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .gitignore -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@mapbox/eslint-config-mapbox", 4 | "prettier" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | dist 4 | _tmp_assembly 5 | _batfish* 6 | _site 7 | .DS_Store -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .eslintignore -------------------------------------------------------------------------------- /.publisher.yml: -------------------------------------------------------------------------------- 1 | subdomain: labs 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: jammy 2 | language: node_js 3 | node_js: 4 | - 18 5 | cache: 6 | directories: 7 | - $HOME/.npm 8 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @mapbox/studio 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | * The use of sexualized language or imagery 10 | * Personal attacks 11 | * Trolling or insulting/derogatory comments 12 | * Public or private harassment 13 | * Publishing other's private information, such as physical or electronic addresses, without explicit permission 14 | * Other unethical or unprofessional conduct 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) 23 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ] 6 | } -------------------------------------------------------------------------------- /batfish.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./src/md4-shim'); 4 | 5 | const path = require('path'); 6 | // eslint-disable-next-line 7 | const navigationStructure = require('./_tmp_assembly/navigation.json'); 8 | 9 | module.exports = () => { 10 | return { 11 | siteBasePath: '/assembly/', 12 | siteOrigin: 'https://labs.mapbox.com', 13 | outputDirectory: path.join(__dirname, '_site'), 14 | stylesheets: [ 15 | path.join(__dirname, './site/css/hljs.css'), 16 | path.join(__dirname, './dist/assembly.css') 17 | ], 18 | dataSelectors: { 19 | examplesSubNavigationList: () => { 20 | return navigationStructure.navigationList.find( 21 | routeConfig => routeConfig.name === 'Examples' 22 | ).items; 23 | }, 24 | documentationData: () => { 25 | return navigationStructure.navigationList.find( 26 | routeConfig => routeConfig.name === 'Documentation' 27 | ).props.documentationData; 28 | } 29 | }, 30 | fileLoaderExtensions: extensions => extensions.concat(['svg']), 31 | pagesDirectory: path.join(__dirname, './site/pages'), 32 | webpackStaticIgnore: [/copy\.js$/], 33 | vendorModules: ['highlight.js'], 34 | applicationWrapperPath: path.join( 35 | __dirname, 36 | './site/application_wrapper.js' 37 | ), 38 | staticHtmlInlineDeferCss: false 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const buildUserAssets = require('./scripts/build-user-assets'); 4 | 5 | module.exports = { 6 | buildUserAssets 7 | }; 8 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "verbose": true, 3 | "watch": [ 4 | "./src/" 5 | ], 6 | "ignore": [ 7 | "src/color-variants.css", 8 | "src/layout-scales.css" 9 | ], 10 | "ext": "js json css html" 11 | } 12 | -------------------------------------------------------------------------------- /scripts/build-icon-json.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const mkdirp = require('mkdirp'); 5 | const path = require('path'); 6 | const pify = require('pify'); 7 | const timelog = require('./timelog'); 8 | 9 | function buildIconJSON(options) { 10 | if (options == null) { 11 | options = {}; 12 | } 13 | 14 | if (!options.quiet) timelog('Building icon JSON'); 15 | 16 | const outdir = options.outdir || path.join(__dirname, '../_tmp_assembly'); 17 | const outfile = options.outfile || 'icons.json'; 18 | const icons = fs 19 | .readdirSync(path.join(__dirname, '../src/svgs')) 20 | .filter(filename => filename.endsWith('.svg')) 21 | .map(filename => path.basename(filename, '.svg')); 22 | 23 | return pify(mkdirp)(outdir) 24 | .then(() => { 25 | return pify(fs.writeFile)( 26 | path.join(outdir, outfile), 27 | JSON.stringify({ icons }), 28 | 'utf8' 29 | ); 30 | }) 31 | .then(() => timelog('Done building icon JSON')); 32 | } 33 | 34 | module.exports = buildIconJSON; 35 | 36 | if (require.main === module) { 37 | buildIconJSON().catch(err => console.error(err.stack)); 38 | } 39 | -------------------------------------------------------------------------------- /scripts/build-js.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const mkdirp = require('mkdirp'); 6 | const pify = require('pify'); 7 | const UglifyJS = require('uglify-js'); 8 | const timelog = require('./timelog'); 9 | const buildSvgLoader = require('./build-svg-loader'); 10 | 11 | const jsSrcDir = path.join(__dirname, '../src/js'); 12 | 13 | // If you create a new script for assembly.js you must add it here 14 | const jsFiles = [ 15 | path.join(jsSrcDir, 'focus-control.js'), 16 | path.join(jsSrcDir, 'icon-functions.js') 17 | ]; 18 | 19 | /** 20 | * Build JS. 21 | * 22 | * @param {Object} [options] 23 | * @param {string} [options.outfile] - Path to which built JS should be written. 24 | * @param {Object} [options.quiet] - Suppress logs. 25 | * @param {Array} [options.icons] - Array of icon names to include in the 26 | * loader. icon names correspond to SVG file names excluding the `.svg` suffix. 27 | * @return {Promise} 28 | */ 29 | function buildJs(options) { 30 | options = options || {}; 31 | 32 | if (!options.quiet) timelog('Building JS'); 33 | const outfile = 34 | options.outfile || path.join(__dirname, '../dist/assembly.js'); 35 | 36 | return Promise.all([buildSvgLoader(options.icons || []), concatJs()]) 37 | .then(data => { 38 | const allJs = data.join(''); 39 | if (options.unminified) return allJs; 40 | const uglifyResult = UglifyJS.minify(allJs); 41 | if (uglifyResult.error) { 42 | throw uglifyResult.error; 43 | } 44 | return uglifyResult.code; 45 | }) 46 | .then(optimizedJs => { 47 | return pify(mkdirp)(path.dirname(outfile)).then(() => { 48 | return pify(fs.writeFile)(outfile, optimizedJs); 49 | }); 50 | }) 51 | .then(() => { 52 | if (!options.quiet) timelog('Done building JS'); 53 | }); 54 | } 55 | 56 | function concatJs() { 57 | const result = []; 58 | // Deterministic order needed for tests 59 | return Promise.all( 60 | jsFiles.map((jsFile, index) => { 61 | return pify(fs.readFile)(jsFile, 'utf8').then(jsFileContent => { 62 | result[index] = jsFileContent; 63 | }); 64 | }) 65 | ).then(() => result.join('')); 66 | } 67 | 68 | module.exports = buildJs; 69 | 70 | if (require.main === module) { 71 | buildJs().catch(err => console.error(err.stack)); 72 | } 73 | -------------------------------------------------------------------------------- /scripts/build-user-assets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const buildCss = require('./build-css'); 5 | const buildJs = require('./build-js'); 6 | 7 | function buildUserAssets(outdir, options) { 8 | options = options || {}; 9 | outdir = outdir || path.join(__dirname, '../dist'); 10 | 11 | const buildCssOptions = Object.assign( 12 | { 13 | outfile: path.join(outdir, 'assembly.css') 14 | }, 15 | options 16 | ); 17 | 18 | const buildJsOptions = { 19 | outfile: path.join(outdir, 'assembly.js'), 20 | icons: options.icons || false, 21 | quiet: options.quiet || false 22 | }; 23 | 24 | return Promise.all([buildCss(buildCssOptions), buildJs(buildJsOptions)]); 25 | } 26 | 27 | module.exports = buildUserAssets; 28 | 29 | if (require.main === module) { 30 | buildUserAssets().catch(err => console.error(err.stack)); 31 | } 32 | -------------------------------------------------------------------------------- /scripts/check-size.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | const pify = require('pify'); 6 | const child_process = require('child_process'); 7 | const prettyBytes = require('pretty-bytes'); 8 | const gzipSize = require('gzip-size'); 9 | 10 | child_process.execSync( 11 | 'node_modules/.bin/npm-run-all --parallel build:js build:css' 12 | ); 13 | 14 | const readCss = pify(fs.readFile)( 15 | path.join(__dirname, '../dist/assembly.min.css') 16 | ); 17 | const readJs = pify(fs.readFile)(path.join(__dirname, '../dist/assembly.js')); 18 | 19 | Promise.all([readCss, readJs]).then(data => { 20 | const cssBuffer = data[0]; 21 | const jsBuffer = data[1]; 22 | const cssSize = prettyBytes(Buffer.byteLength(cssBuffer, 'utf8')); 23 | const jsSize = prettyBytes(Buffer.byteLength(jsBuffer, 'utf8')); 24 | const cssGzipSize = prettyBytes(gzipSize.sync(cssBuffer)); 25 | const jsGzipSize = prettyBytes(gzipSize.sync(jsBuffer)); 26 | 27 | console.log(`CSS: ${cssSize} (minified) => ${cssGzipSize} (gzipped)`); 28 | console.log(`SVG: ${jsSize} => ${jsGzipSize} (gzipped)`); 29 | }); 30 | -------------------------------------------------------------------------------- /scripts/clean-svgs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const xml2js = require('xml2js'); 5 | 6 | const parseString = xml2js.parseString; 7 | 8 | fs.readdir('./src/svgs/', (err, files) => { 9 | const svgFiles = files.filter( 10 | file => 11 | file 12 | .split('.') 13 | .pop() 14 | .indexOf('svg') !== -1 15 | ); 16 | 17 | svgFiles.forEach(fileName => { 18 | fs.readFile('./src/svgs/' + fileName, 'utf8', (err, file) => { 19 | if (err) return console.error(err); 20 | parseString(file, (err, parsed) => { 21 | if (err) return console.error(err); 22 | cleanSvg(parsed.svg, fileName); 23 | }); 24 | }); 25 | }); 26 | }); 27 | 28 | function cleanSvg(svg, fileName) { 29 | svg.$.viewBox = '0 0 18 18'; 30 | delete svg.metadata; 31 | delete svg.defs; 32 | delete svg['sodipodi:namedview']; 33 | 34 | // Remove most properties from svg. 35 | Object.keys(svg.$).forEach(k => { 36 | if (!['xmlns', 'viewBox'].includes(k)) delete svg.$[k]; 37 | }); 38 | 39 | function cleanPaths(path) { 40 | path.forEach(p => { 41 | // Remove fill from paths. 42 | if (p.$ && Object.keys(p.$).length) { 43 | Object.keys(p.$).forEach(k => { 44 | if (!['d', 'fill-rule', 'clip-rule'].includes(k)) delete p.$[k]; 45 | }); 46 | } 47 | }); 48 | } 49 | 50 | function cleanGroups(group) { 51 | group.forEach(g => { 52 | if (g.$ && Object.keys(g.$).length) { 53 | // Remove all properties from groups 54 | Object.keys(g.$).forEach(k => { 55 | delete g.$[k]; 56 | }); 57 | } 58 | 59 | if (g.path) { 60 | cleanPaths(g.path); 61 | } 62 | 63 | if (g.g) { 64 | cleanGroups(g.g); 65 | } 66 | }); 67 | } 68 | 69 | if (svg.g) cleanGroups(svg.g); 70 | if (svg.path) cleanPaths(svg.path); 71 | 72 | const builder = new xml2js.Builder({ 73 | rootName: 'svg', 74 | renderOpts: { pretty: true } 75 | }); 76 | const xml = builder.buildObject(svg); 77 | 78 | fs.writeFile('./src/svgs/' + fileName, xml, 'utf8', err => { 79 | if (err) return console.error(err); 80 | console.log(`cleaned ${fileName}`); 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const globby = require('globby'); 6 | const S3 = require('aws-sdk/clients/s3'); 7 | const mime = require('mime'); 8 | const pkg = require('../package'); 9 | 10 | const bucket = new S3({ 11 | params: { 12 | Bucket: 'mapbox-assembly/v' + pkg.version 13 | } 14 | }); 15 | 16 | globby(path.join(__dirname, '../dist/assembly*')) 17 | .then(files => { 18 | const uploadFiles = files.map(file => { 19 | return bucket 20 | .upload({ 21 | ACL: 'public-read', 22 | Key: path.basename(file), 23 | Body: fs.createReadStream(file), 24 | ContentType: mime.getType(file) 25 | }) 26 | .promise(); 27 | }); 28 | 29 | return Promise.all(uploadFiles); 30 | }) 31 | .then(() => { 32 | console.log('DEPLOYED Assembly', pkg.version); 33 | }) 34 | .catch(err => { 35 | console.log(err.stack); 36 | }); 37 | -------------------------------------------------------------------------------- /scripts/order-sections.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | 5 | function orderSections(entries) { 6 | function getSection(title) { 7 | const sectionEntry = entries.find(entry => { 8 | if (!entry.title) return false; 9 | return entry.title.toLowerCase() === title.toLowerCase(); 10 | }); 11 | 12 | if (sectionEntry === undefined) { 13 | throw new Error(`Could not find entry with title "${title}"`); 14 | } 15 | 16 | if (sectionEntry.members) { 17 | sectionEntry.members = _.sortBy(sectionEntry.members, 'title'); 18 | } 19 | 20 | return sectionEntry; 21 | } 22 | 23 | // We need to add to this list when we 24 | // add new primary sections 25 | const sections = [ 26 | getSection('typography'), 27 | getSection('layout'), 28 | getSection('theming'), 29 | getSection('Colors'), 30 | getSection('icons'), 31 | getSection('buttons'), 32 | getSection('links'), 33 | getSection('forms'), 34 | getSection('tables'), 35 | getSection('animations'), 36 | getSection('triangles'), 37 | getSection('miscellaneous') 38 | ]; 39 | 40 | return sections; 41 | } 42 | 43 | module.exports = orderSections; 44 | -------------------------------------------------------------------------------- /scripts/timelog.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function timeLog(str) { 4 | const now = new Date(); 5 | console.log( 6 | `[${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}] ${str}` 7 | ); 8 | } 9 | 10 | module.exports = timeLog; 11 | -------------------------------------------------------------------------------- /scripts/watch-assembly-assets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const child_process = require('child_process'); 4 | const path = require('path'); 5 | 6 | function handleError(err) { 7 | throw err; 8 | } 9 | 10 | const nodemonProcess = child_process.spawn('node_modules/.bin/nodemon', [ 11 | '--on-change-only', 12 | path.join(__dirname, './build-user-assets.js') 13 | ]); 14 | 15 | nodemonProcess.on('error', handleError); 16 | nodemonProcess.stdout.on('data', data => { 17 | console.log(data.toString().trim()); 18 | }); 19 | nodemonProcess.stderr.on('data', data => { 20 | console.log(data.toString().trim()); 21 | }); 22 | -------------------------------------------------------------------------------- /site/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true 5 | }, 6 | "extends": [ 7 | "@mapbox/eslint-config-mapbox/react", 8 | "@mapbox/eslint-config-mapbox/import", 9 | "@mapbox/eslint-config-mapbox/promise", 10 | "prettier" 11 | ], 12 | "parser": "@babel/eslint-parser", 13 | "rules": { 14 | "react/prop-types": "off" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /site/application_wrapper.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | if (typeof window !== 'undefined') { 4 | import(/* webpackChunkName: "assembly-js" */ '../dist/assembly.js'); // eslint-disable-line import/no-unresolved 5 | } 6 | 7 | export default class ApplicationWrapper extends React.Component { 8 | render() { 9 | return this.props.children; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /site/catalog/bleeds.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export class Bleeds extends React.Component { 4 | render() { 5 | return ( 6 |
7 |

8 | Bleeds 9 |

10 | 11 |
12 |
13 |
Right bleed
14 |
15 |
16 |
17 |
18 |
Left bleed
19 |
20 |
21 |
22 |
23 |
Right bleed at xl
24 |
25 |
26 |
27 |
28 |
29 | Right bleed until xl 30 |
31 |
32 |
33 |
34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /site/catalog/buttons.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const colors = [ 4 | null, 5 | 'gray', 6 | 'pink', 7 | 'red', 8 | 'orange', 9 | 'yellow', 10 | 'green', 11 | 'blue', 12 | 'purple', 13 | 'darken10', 14 | 'darken25', 15 | 'darken50', 16 | 'darken75' 17 | ]; 18 | 19 | const lightenColors = [ 20 | 'lighten10', 21 | 'lighten25', 22 | 'lighten50', 23 | 'lighten75', 24 | 'white' 25 | ]; 26 | 27 | const getButtonEls = (color, i) => { 28 | let buttonFillClass = 'btn'; 29 | let buttonStrokeClass = 'btn btn--stroke'; 30 | if (color !== null) { 31 | buttonFillClass += ` btn--${color}`; 32 | buttonStrokeClass += ` btn--${color}`; 33 | } 34 | 35 | return ( 36 |
37 |
38 | 39 |
40 |
41 | 44 |
45 |
46 | 47 |
48 |
49 | 52 |
53 | {!/^(darken10|darken25|lighten10|lighten25)$/.test(color) ? ( 54 | 55 |
56 | 57 |
58 |
59 | 62 |
63 |
64 | ) : ( 65 | '' 66 | )} 67 |
68 | ); 69 | }; 70 | 71 | export class Buttons extends React.Component { 72 | render() { 73 | const buttonEls = colors.map(getButtonEls); 74 | const lightenButtonEls = lightenColors.map(getButtonEls); 75 | 76 | return ( 77 |
78 |

79 | Buttons 80 |

81 | 82 | {buttonEls} 83 | 84 |
{lightenButtonEls}
85 |
86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /site/catalog/checkboxes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const colors = [ 4 | null, 5 | 'gray', 6 | 'pink', 7 | 'red', 8 | 'orange', 9 | 'yellow', 10 | 'green', 11 | 'blue', 12 | 'purple' 13 | ]; 14 | 15 | export class Checkboxes extends React.Component { 16 | render() { 17 | const checkmark = ( 18 | 19 | 20 | 21 | ); 22 | 23 | const checkboxes = colors.map((color, i) => { 24 | let checkboxClass = 'checkbox mr6'; 25 | if (color !== null) { 26 | checkboxClass += ` checkbox--${color}`; 27 | } 28 | 29 | return ( 30 |
31 | 36 | 41 |
42 | ); 43 | }); 44 | 45 | return ( 46 |
47 |

48 | Checkboxes 49 |

50 | 51 |
52 | 53 | 54 |
55 | 56 | {checkboxes} 57 |
58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /site/catalog/links.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const colors = [ 4 | null, 5 | 'gray', 6 | 'pink', 7 | 'red', 8 | 'orange', 9 | 'yellow', 10 | 'green', 11 | 'blue', 12 | 'purple', 13 | 'lighten25', 14 | 'lighten50', 15 | 'lighten75', 16 | 'darken25', 17 | 'darken50', 18 | 'darken75', 19 | 'black', 20 | 'white' 21 | ]; 22 | 23 | function LinkEl(props) { 24 | let linkClasses = 'link col w-1/3 inline mb6'; 25 | if (props.color) linkClasses += ` link--${props.color}`; 26 | return ( 27 |
28 |
Click me!
29 |
Click me!
30 |
Active
31 |
32 | ); 33 | } 34 | 35 | export class Links extends React.Component { 36 | render() { 37 | return ( 38 |
39 |

40 | Links 41 |

42 | 43 |
44 |
45 |
46 | Standard 47 |
48 |
49 | Underline on hover 50 |
51 |
52 | Active 53 |
54 |
55 | {colors.map(c => )} 56 |
57 |
58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /site/catalog/pills.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export class Pills extends React.Component { 4 | render() { 5 | return ( 6 |
7 |

8 | Button pills 9 |

10 | 11 |
12 | 13 | 16 | 19 | 20 |
21 | 22 |
23 | 26 | 29 | 32 | 35 |
36 | 37 |
38 | 41 | 44 | 47 | 50 |
51 | 52 |
53 | 56 | 59 | 62 | 65 |
66 |
67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /site/catalog/radios.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const colors = [ 4 | null, 5 | 'gray', 6 | 'pink', 7 | 'red', 8 | 'orange', 9 | 'yellow', 10 | 'green', 11 | 'blue', 12 | 'purple' 13 | ]; 14 | 15 | export class Radios extends React.Component { 16 | render() { 17 | const radios = colors.map((color, i) => { 18 | let radioClass = 'radio mr6'; 19 | let id = 'radio'; 20 | if (color !== null) { 21 | radioClass += ` radio--${color}`; 22 | id += `-${color}`; 23 | } 24 | 25 | return ( 26 |
27 |